Java 使用JMockit模拟自动连线接口实现
我们正在为一个类编写JUnit测试,该类使用Spring自动连接来注入依赖项,该依赖项是接口的某个实例。由于被测试的类从未显式地实例化依赖项或将其传递到构造函数中,因此JMockit似乎也没有义务实例化它 到目前为止,我们一直在使用SpringRunner为我们提供Spring负载模拟依赖项,这很有效。我们不喜欢的两件事是:1)每次运行测试时都必须加载和初始化Spring框架,这不是很快;2)我们被迫显式地将所有模拟依赖项创建为真实类,这是JMockit帮助消除的 下面是我们正在测试的一个简化示例:Java 使用JMockit模拟自动连线接口实现,java,spring,junit,mocking,jmockit,Java,Spring,Junit,Mocking,Jmockit,我们正在为一个类编写JUnit测试,该类使用Spring自动连接来注入依赖项,该依赖项是接口的某个实例。由于被测试的类从未显式地实例化依赖项或将其传递到构造函数中,因此JMockit似乎也没有义务实例化它 到目前为止,我们一直在使用SpringRunner为我们提供Spring负载模拟依赖项,这很有效。我们不喜欢的两件事是:1)每次运行测试时都必须加载和初始化Spring框架,这不是很快;2)我们被迫显式地将所有模拟依赖项创建为真实类,这是JMockit帮助消除的 下面是我们正在测试的一个简化示
public class UnitUnderTest {
@Autowired
ISomeInterface someInterface;
public void callInterfaceMethod() {
System.out.println( "UnitUnderTest.callInterfaceMethod calling someInterface.doSomething");
someInterface.doSomething();
}
}
所以,问题是,有没有办法让JMockit创建一个模拟的
someInterface
?您可以使用org.springframework.test.util.ReflectionTestUtils
在您的测试用例中显式地注入模拟的someInterface
请参见JMockit将始终实例化模拟接口(最终模拟字段除外),但这仅发生在测试代码中。它不会自动将实例注入测试代码中 您必须手动注入模拟实例。例如:
public class SomeTest
{
@Autowired UnitUnderTest unitUnderTest;
@Mocked ISomeInterface theMock; // created and assigned automatically
@Test
public void testSomeMethod()
{
Deencapsulation.setField(unitUnderTest, theMock);
//proceed with unit test here
}
}
@Component
public class AClass {
@Autowired
private Bean1 bean1;
@Autowired
@Qualifier("my-dashed-name")
private AmqpTemplate rpcTemplate;
}
mockit.Deencapsulation
是一个基于反射的实用程序类,它允许您调用私有方法、get/set字段等。并提供上述提示,作为一个对JMockit很陌生的人,我发现以下内容最有用:JMockit提供了Deencapsulation
类,允许您设置私有相关字段的值(无需将Spring库拖入),以及MockUp
类,该类允许您显式创建接口的实现并模拟接口的一个或多个方法。以下是我最终解决这个特殊案件的方式:
@Before
public void setUp() {
IMarketMakerDal theMock = new MockUp <IMarketMakerDal>() {
@Mock
MarketMakerDcl findByMarketMakerGuid( String marketMakerGuid ) {
MarketMakerDcl marketMakerDcl = new MarketMakerDcl();
marketMakerDcl.setBaseCurrencyCode( CURRENCY_CODE_US_DOLLAR );
return marketMakerDcl;
}
}.getMockInstance();
setField( unitUnderTest, theMock );
}
@之前
公共作废设置(){
IMarketMakerDal theMock=新模型(){
@嘲弄
MarketMakerDcl FindByMarketMarkerGuid(字符串marketMakerGuid){
MarketMakerDcl MarketMakerDcl=新的MarketMakerDcl();
marketMakerDcl.setBaseCurrencyCode(货币代码美元);
返回市场makerdcl;
}
}.getMockInstance();
设置字段(测试中的单元,模块);
}
谢谢大家的帮助。感谢那些遇到的人
java.lang.IllegalStateException: Missing @Injectable for field ***
或
使用jmockit
模拟spring
(或spring boot
)框架中的autowired
字段时出错,我执行了以下两个步骤以避免上述错误:
@Tested(fullyInitialized=true)
而不是@Tested
1.18
或以前的版本如果接口有@Qualifier注释,则需要将@Injectable字段的名称与Qualifier中的名称完全相同 以下是引自: 在查找匹配的@Injectable或@Tested值时,将使用来自JavaEE(@Resource(name),@Named)或Spring框架(@Qualifier)的字段注释中指定的自定义名称。当该名称包含-(破折号)或时。(点)字符,则使用相应的大小写名称 例如:
public class SomeTest
{
@Autowired UnitUnderTest unitUnderTest;
@Mocked ISomeInterface theMock; // created and assigned automatically
@Test
public void testSomeMethod()
{
Deencapsulation.setField(unitUnderTest, theMock);
//proceed with unit test here
}
}
@Component
public class AClass {
@Autowired
private Bean1 bean1;
@Autowired
@Qualifier("my-dashed-name")
private AmqpTemplate rpcTemplate;
}
单元测试类:
public class AClassTest {
@Injectable
private Bean1 bean1;
@Injectable
private AmqpTemplate myDashedName;
@Tested
private AClass aClass = new AClass();
}
另外,对于每个@autowiredbean,也不需要使用setfield,当@Tested类实例化时,所有字段都会自动注入。在JMockit版本上测试。1.30另请参见:这确实是一门有用的课程。尽管如此,必须显式地创建mock还是挫败了首先使用JMockit的主要原因之一。这非常有用。我手工创建mock,并且在测试的类中有一个autowired属性。这允许我将测试中的属性设置为mock,而无需编辑测试中的代码!很好。请注意:自从这个答案发布以来,JMockit增加了对模拟对象自动注入测试类的支持。在本例中,将
@Autowired
替换为@Tested
,将@mock
替换为@Injectable
。哇@Rogério!太好了!JMockit是如此强大。。。我很喜欢@Rogério jmockit coverage tool可以为mockito生成报告吗?我们的遗留测试代码使用mockito。任何链接都是有用的。@yuyue007是的,覆盖工具不需要jmockit.jar的存在,尽管它存在时会更容易。您需要使用“-javaagent:jmockit coverage.jar”JVM初始化参数(来自命令行/IDE或Ant/Maven/Gradle构建脚本)。细节在这里。@Rogério Cool!我在使用泛型类型的cascade-mock时遇到了一些问题,我在github中创建了一个问题,您是否可以帮助检查哪里出错,或者这是否是一个bug。非常感谢。