Java 在同一个类中模拟其他公共方法是一种好的做法吗
例如:Java 在同一个类中模拟其他公共方法是一种好的做法吗,java,unit-testing,mocking,Java,Unit Testing,Mocking,例如: public class NumberService { public boolean isNaturalNumber(int num) { return num > 0; } public String getClassificationInfo(int num) { return isNaturalNumber(num) ? num + "is a natural number" : num + "is not a natural number"; } }
public class NumberService {
public boolean isNaturalNumber(int num) {
return num > 0;
}
public String getClassificationInfo(int num) {
return isNaturalNumber(num) ? num + "is a natural number" : num + "is not a natural number";
}
}
这里有两个公共方法,方法getClassificationInfo
称为方法isNaturalNumber
在测试getClassificationInfo
时模拟isNaturalNumber
是否是一种好的做法
像这样:
@RunWith(MockitoJUnitRunner.class)
public class NumberServiceTest {
@Spy
private NumberService numberService;
@Test
public void test_getClassificationInfo_when_is_natural_number() {
int num = generateInt();
doReturn(true).when(numberService).isNaturalNumber(num);
String classificationInfo = numberService.getClassificationInfo(num);
assertThat(classificationInfo).isEqualTo(num + "is a natural number");
}
@Test
public void test_getClassificationInfo_when_is_not_natural_number() {
int num = generateInt();
doReturn(false).when(numberService).isNaturalNumber(num);
String classificationInfo = numberService.getClassificationInfo(num);
assertThat(classificationInfo).isEqualTo(num + "is not a natural number");
}
// the other test for isNaturalNumber
private int generateInt() {
return new Random().nextInt();
}
}
在这种特殊情况下,模拟调用的方法是没有意义的。然而,这不仅仅是因为它是同一类的方法。事实上,有时会专门引入同一类的方法来模拟它们。例如,如果在类中处理通过文件I/O获得的某些数据,则可以将文件I/O隔离到其自己的方法中。然后,您可以使用文件I/O方法的模拟版本测试数据处理 但是,在这种情况下,没有充分的理由在
getClassificationInfo
的测试中模拟isNaturalNumber
:方法isNaturalNumber
具有确定性行为,不会导致不可接受的长执行时间。通过模拟isNaturalNumber
在getClassificationInfo
的一个测试中故意行为错误的情况,您似乎也不太可能获得很多好处
你不必武断地嘲笑一切。例如,您也不会模拟标准库数学函数,如
sin
或cos
,因为它们在大多数情况下也不会导致问题。嘲笑应该是有原因的。因此,如果你考虑嘲弄一个函数或方法,你应该知道你将要解决的问题。如果没有问题要解决,不要模拟。在这种特殊情况下,模拟调用的方法没有意义。然而,这不仅仅是因为它是同一类的方法。事实上,有时会专门引入同一类的方法来模拟它们。例如,如果在类中处理通过文件I/O获得的某些数据,则可以将文件I/O隔离到其自己的方法中。然后,您可以使用文件I/O方法的模拟版本测试数据处理
但是,在这种情况下,没有充分的理由在getClassificationInfo
的测试中模拟isNaturalNumber
:方法isNaturalNumber
具有确定性行为,不会导致不可接受的长执行时间。通过模拟isNaturalNumber
在getClassificationInfo
的一个测试中故意行为错误的情况,您似乎也不太可能获得很多好处
你不必武断地嘲笑一切。例如,您也不会模拟标准库数学函数,如
sin
或cos
,因为它们在大多数情况下也不会导致问题。嘲笑应该是有原因的。因此,如果你考虑嘲弄一个函数或方法,你应该知道你将要解决的问题。如果没有问题要解决,就不要模拟。不,这不是一个好的做法,因为我们应该在涉及其他模块/类对象的地方模拟存根
例如:
然后,您应该模拟B的someMethod(),而不应该模拟A的someLogic(),因为您正在单元测试A的AdoningSomebWork()方法。如果你嘲笑某个逻辑();在单元测试中,可能会出现代码中断的情况。不,这不是一个好的做法,因为我们应该在涉及其他模块/类对象的地方模拟存根 例如:
然后,您应该模拟B的someMethod(),而不应该模拟A的someLogic(),因为您正在单元测试A的AdoningSomebWork()方法。如果你嘲笑某个逻辑();在单元测试中,可能会出现代码中断的情况。您不需要使用间谍。如果您正在测试
NumberService
,那么它应该是真正的类。在您的示例中,getClassificationInfo()
的实现取决于isNaturalNumber()
的实现。如果你得到了错误的模拟,你的测试可能会通过,但实际上实现可能仍然是错误的。你不应该模拟类本身,而应该创建该类的对象并测试结果。。。只有在类中有依赖项时,模拟才会出现。。例如,如果您在NumberService
上有其他服务,那么您可能会模拟该服务并将那些模拟的内容存根为空,除非您的测试变得缓慢-然后模拟依赖关系使测试变得缓慢(访问外部资源,如数据库、Web服务、文件系统等),除非准备测试变得非常复杂,否则您将使用复杂的配置模拟依赖项。我的问题是:isNaturalNumber()
是否被其他代码使用?它真的需要公开吗?如果不是,那么它只是一个应该被显式测试的实现细节。@TimothyTruckle是的,isNaturalNumber被其他类使用,您不需要使用间谍。如果您正在测试NumberService
,那么它应该是真正的类。在您的示例中,getClassificationInfo()
的实现取决于isNaturalNumber()
的实现。如果你得到了错误的模拟,你的测试可能会通过,但实际上实现可能仍然是错误的。你不应该模拟类本身,而应该创建该类的对象并测试结果。。。只有在类中有依赖项时,模拟才会出现。。例如,如果您在NumberService
上有其他服务,那么您可能会模拟该服务并将那些模拟的内容存根为空,除非您的测试变得缓慢-然后模拟依赖关系使测试变得缓慢(访问外部资源,如数据库、Web服务、文件系统等),除非准备测试变得非常复杂,否则您将使用复杂的配置模拟依赖项。我的问题是:isNaturalNumber()
是否被其他代码使用?这真的很有趣吗
public class A{
private B aObj;
public void aDoingSomeBWork(){
aObj.someMethod();
someLogic();
}
private/public/any modifier void someLogic(){
//some logic
}
}
public class B{
public void someMethod(){}
}