Java Jmockit:如何验证在特定实例上调用了方法
我正在Java1.7上使用JMockit1.15 我想验证一些经过测试的代码是否先创建一个特定类(ExampleClass)的新实例,然后在该实例上调用一个方法。 我尝试了很多方法,使用了验证、期望、模拟、注射等多种不同的方法,但都没有成功 下面是一个例子 示例类是一个类;我将模拟它,我想验证它是如何使用的Java Jmockit:如何验证在特定实例上调用了方法,java,unit-testing,jmockit,Java,Unit Testing,Jmockit,我正在Java1.7上使用JMockit1.15 我想验证一些经过测试的代码是否先创建一个特定类(ExampleClass)的新实例,然后在该实例上调用一个方法。 我尝试了很多方法,使用了验证、期望、模拟、注射等多种不同的方法,但都没有成功 下面是一个例子 示例类是一个类;我将模拟它,我想验证它是如何使用的 public class ExampleClass { final double id = Math.random(); public ExampleClass() {
public class ExampleClass {
final double id = Math.random();
public ExampleClass() {
}
public void doSomething() {
System.out.println("I did something - " + id);
}
}
ExampleClassUser包含我要测试的逻辑
请注意,ErrorUsage()生成ExampleClass的两个实例,但总是在第一个实例上调用doSomething()
public class ExampleClassUser {
public void rightUsage() {
final ExampleClass exampleClass1 = new ExampleClass();
exampleClass1.doSomething();
final ExampleClass exampleClass2 = new ExampleClass();
exampleClass2.doSomething();
}
public void wrongUsage() {
final ExampleClass exampleClass1 = new ExampleClass();
exampleClass1.doSomething();
final ExampleClass exampleClass2 = new ExampleClass();
exampleClass1.doSomething();
}
}
示例ClassUserTest是我想要构建的测试。
它应该检查对rightUsage()或ErrorUsage()的每个方法调用
测试实例化对象的方法有点困难,因为在方法之外,您无法访问新创建的实例。解决方法是使用
工厂
创建ExampleClass
实例,并将其作为依赖项传递给ExampleClassUser
。现在您使用的是c控制,因为您可以模拟工厂以返回您需要的任何对象(模拟、自定义单元测试对象等),并且由于您可以访问这些对象,因此可以对它们进行断言
另一种方法是,如果您不强烈需要确保调用了对象/方法,则不断言调用了正确的对象/方法,而是断言这些调用的效果。这将有利于将测试与方法实现分离。这种方法只有在doSomething()时才可行
具有无需访问对象即可检测到的副作用,并且可能涉及复杂的设置
例如,如果
doSomething()
返回一个素数,每次调用它都返回下一个素数(第一次调用将返回2,第二次调用将返回3,依此类推),并且测试的方法将两个数相加并返回它们(是的,我知道一个愚蠢的示例),那么您可以检测doSomething()对两个不同的对象调用了
,因为它们的总和是4。如果对同一个对象调用了doSomething()
,则返回的结果是5。对于JMockit 1.17或更高版本,以下版本的测试将起作用(即,它将按预期失败):
你认为这是一个Jmockit限制还是一个糟糕的测试模式?这不是一个Jmockit限制,而是不可测试的代码。基本上,因为对创建对象的引用只能在封闭方法的范围内访问,所以从方法之外几乎无法完成。现在,如果你想测试doSomething()在适当的对象上调用,然后将对象实例化移到方法之外的某个地方(和jmockit)拥有访问权限,或者……我会将此方法添加到答案中,因为它对其他在该页面上运行的人会有帮助。测试可以用JMockit编写,但看起来不太好。我认为您应该描述您需要解决的实际测试问题,而不是展示一个人为的示例。我打赌真正的问题会更容易。嗯,我尝试了通过一个特别的示例,我将更清楚地说明它,并且它是可执行的,但是,正如您所要求的,我将报告真实的情况。我有一个表示ssh调用的类(使用构造函数
SshCommand(String命令,Host targetHost)
),还有一个execute()
method。这个类的许多实例在整个测试代码中都被使用。我希望我的单元测试能够检查哪些实例被创建,哪些实例上使用了execute()
方法。我在下面看到了您的示例解决方案,这正是我所想的(我只需要等待新版本发布)。您为什么说“它看起来不好?在JMockit 1.16或更老版本上它看起来不好,因为测试必须使用带有调用参数的委托
对象,这样它才能访问新实例并将其保存到测试类中的字段中。JMockit 1.17+使用内部“等效实例”“将方法期望值与以前匹配的构造函数期望值匹配时进行映射,这样测试就简单多了。您认为在验证块中内联编写对象创建和方法调用(new ExampleClass().doSomething();
)而不是将新创建的实例分配给变量是一样的吗?”?(这似乎有效,但我不太确定它是否正确);为了清楚起见,我只使用了局部变量。
import mockit.FullVerificationsInOrder;
import mockit.Mocked;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(mockit.integration.junit4.JMockit.class)
public class ExampleClassUserTest {
@Test
public void testUsage(final @Mocked ExampleClass exampleClass) {
//new ExampleClassUser().rightUsage();
new ExampleClassUser().wrongUsage();
new FullVerificationsInOrder() {{
new ExampleClass();
exampleClass.doSomething();
new ExampleClass();
exampleClass.doSomething();
}};
}
}
@Test
public void testUsage(@Mocked ExampleClass exampleClass)
{
new ExampleClassUser().wrongUsage();
new FullVerificationsInOrder() {{
ExampleClass e1 = new ExampleClass(); // matches first new instance
e1.doSomething(); // matches only on instances equivalent to "e1"
// Same as before, now for the second instance.
ExampleClass e2 = new ExampleClass();
e2.doSomething(); // fails with a "missing invocation"
}};
}