Java 重构与测试

Java 重构与测试,java,unit-testing,junit,mockito,test-refactoring,Java,Unit Testing,Junit,Mockito,Test Refactoring,我试图以某种方式进行单元测试的场景示例: 方法获取三个参数:公司名称,飞机编号1,飞机编号2 public Double getDistanceBetweenPlanes(Sting company, String plane1, String plane2) { -Apply some validation logic to see that plane numbers and company realy exists -Use complex geLocation and setel

我试图以某种方式进行单元测试的场景示例:

方法获取三个参数:
公司名称
飞机编号1
飞机编号2

public Double getDistanceBetweenPlanes(Sting company, String plane1, String plane2)
{
  -Apply some validation logic to see that plane numbers and company realy exists
  -Use complex geLocation and setelate data to get plane location

  return plane1.geoLocation() - plane2.geoLocation() ;
}
现在,我想对这个进行单元测试

我没有真实的飞机号码,也没有与卫星的实时连接

尽管如此,我还是希望能够以某种方式模拟整个过程,以便能够测试这个API。
有关于如何重构它的建议吗?要创建任何新的公共方法来进行测试吗?

您可以使用类似jmock或easy mock的mock

使用jmock,您可以编写如下内容:

@Test
public testMethod(){
 Mockery context = new Mockery();
 plane1 = context.mock(Plane.class);
 plane2 = context.mock(Plane.class);

 context.expectations(new Expectations(){{
   oneOf(plane1).geoLocation(); will(returnValue(integerNumber1));
   oneOf(plane2).geoLocation(); will(returnValue(integerNumber2));
 }});
 assertEquals(
   instanceUnderTest.method(plane1,plane2),
   integerNumber1-integerNumber2
 )
 context.assertIsSatisfied()
}  

最后一个方法将确保调用根据期望设置的方法。如果没有引发异常,测试就会失败。

通常在重构未经测试的代码时,我指的是我在练习TDD和BDD时会做什么

所以首先我要写一个简单的合同,一行=一个需求(现有代码)。 然后在编写测试代码时,我可能会注意到一些我不想测试的东西。在这种情况下,DI将帮助您删除对另一个类负有不同责任的代码。在进行对象设计时,重点关注具有不同关注点的对象之间的行为和交互非常重要。Mockito具有别名类BDDMockito,可以帮助您支持这种方法

在你的情况下,这里有一个你可以做的例子

公共类平面定位器{
私人公司供应商公司供应商;
私人飞机供应商公司供应商;
私有位置util LocationUtil;
//构造函数注入还是属性注入
public Double获取平面之间的距离(字符串companyId、字符串plane1Id、字符串plane2Id){
Company Company=companyProvider.get(公司);
PlanePlane1=planeProvider.get(plane1Id);
PlanePlane1=planeProvider.get(plane1Id);
返回locationUtil.distance(plane1.geoLocation(),plane2.geoLocation());
}
}
一个简单的JUnit测试可能如下所示(使用mockito 1.9.0的特性):

@RunWith(MockitoJUnitRunner.class)
公开课考试{
@模拟公司供应商模拟公司供应商;
@模拟平面提供者模拟平面提供者;
@模拟LocationUtil LocationUtil;
@InjectMocks卫星计划探测仪测试计划探测仪;
@测试公共空间应使用位置util获取平面和位置之间的距离{
//给定
给定(companyProvider.get(anyString()).willReturn(newcompany());
给定(planeProvider.get(anyString()))
.willReturn(Plane.builder().withLocation(新位置(“A”))
.willReturn(Plane.builder().withLocation(新位置(“B”));
//什么时候
测试的平面指示器。获取平面之间的距离(“AF”、“1251”、“721”);
//然后
验证(locationUtil).距离(isA(Location.class)、isA(Location.class));
}
//平面定位器的其他更具体测试
}
您将注入以下依赖项,每个依赖项都有自己的单元测试来描述类的行为,考虑到输入和协作者:

公共类DefaultCompanyProvider实现CompanyProvider{
上市公司get(字符串companyId){
companyIdValidator.validate(companyId);
//检索/创建公司
返回公司;
}
}
公共类SatellitePlaneProvider实现PlaneProvider{
公共平面get(平面平面ID){
planeIdValidator.validate(planeId);
//使用昂贵的卫星数据检索/创建飞机(例如使用卫星服务)
返回平面;
}
}
使用这种方法,您可以以更低的耦合重构代码。更好地分离关注点将允许更好地理解代码库、更好的可维护性和更容易的演化


我还想让您在这篇博文中进一步阅读著名的Bob Martin叔叔在TDD中的转换优先级前提

谢谢,但问题是主API方法的输入不是一个平面对象,而是一个带平面ID的字符串,基于带平面ID和公司ID的查询,在调用的方法的作用域内创建了一个平面对象。这正是我要找的。我承认我有点不舒服,因为它似乎为一些功能分配了代码,但这显然是值得学习的东西。