tea*_*bot 276 junit spring annotations dependency-injection mockito
我想将一个Mockito模拟对象注入一个Spring(3+)bean中,以便使用JUnit进行单元测试.我的bean依赖项目前通过@Autowired
在私有成员字段上使用注释来注入.
我考虑过使用ReflectionTestUtils.setField
但我希望注入的bean实例实际上是一个代理,因此不会声明目标类的私有成员字段.我不希望为依赖创建一个公共setter,因为我将修改我的界面纯粹是为了测试的目的.
我遵循了Spring社区给出的一些建议,但是没有创建模拟并且自动连线失败:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
Run Code Online (Sandbox Code Playgroud)
我目前遇到的错误如下:
...
Caused by: org...NoSuchBeanDefinitionException:
No matching bean of type [com.package.Dao] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {
@org...Autowired(required=true),
@org...Qualifier(value=dao)
}
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)
Run Code Online (Sandbox Code Playgroud)
如果我将constructor-arg
值设置为无效,则在启动应用程序上下文时不会发生错误.
amr*_*mra 128
最好的方法是:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
Run Code Online (Sandbox Code Playgroud)
更新
在上下文文件中,必须在任何自动装配字段之前列出此模拟,具体取决于它的声明.
小智 107
@InjectMocks
private MyTestObject testObject;
@Mock
private MyDependentObject mockedObject;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
Run Code Online (Sandbox Code Playgroud)
这会将任何模拟对象注入测试类.在这种情况下,它会将mockedObject注入testObject.这是上面提到的,但这里是代码.
Pio*_*zda 62
我有一个使用Spring Java Config和Mockito的非常简单的解决方案:
@Configuration
public class TestConfig {
@Mock BeanA beanA;
@Mock BeanB beanB;
public TestConfig() {
MockitoAnnotations.initMocks(this); //This is a key
}
//You basically generate getters and add @Bean annotation everywhere
@Bean
public BeanA getBeanA() {
return beanA;
}
@Bean
public BeanB getBeanB() {
return beanB;
}
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*kin 44
鉴于:
@Service
public class MyService {
@Autowired
private MyDAO myDAO;
// etc
}
Run Code Online (Sandbox Code Playgroud)
您可以通过自动装配加载正在测试的类,使用Mockito模拟依赖关系,然后使用Spring的ReflectionTestUtils将模拟注入正在测试的类中.
@ContextConfiguration(classes = { MvcConfiguration.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
@Autowired
private MyService myService;
private MyDAO myDAOMock;
@Before
public void before() {
myDAOMock = Mockito.mock(MyDAO.class);
ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
}
// etc
}
Run Code Online (Sandbox Code Playgroud)
请注意,春节前4.3.1,这种方法不会使用代理服务工作(带注释@Transactional
,或者Cacheable
,例如).这已由SPR-14050修复.
对于早期版本,解决方案是解包代理,如下所述:事务性注释避免了被模拟的服务(ReflectionTestUtils.setField
现在默认情况下是这样)
jfc*_*edo 35
如果你使用的是Spring Boot 1.4,它有一个很棒的方法.只需@SpringBootTest
在你的类和@MockBean
现场使用新品牌,Spring Boot将创建一个这种类型的模拟器,它会将它注入上下文(而不是注入原始的):
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@MockBean
private RemoteService remoteService;
@Autowired
private Reverser reverser;
@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}
}
Run Code Online (Sandbox Code Playgroud)
另一方面,如果您没有使用Spring Boot,或者您使用的是以前的版本,那么您将需要做更多的工作:
创建一个@Configuration
将mocks注入Spring上下文的bean:
@Configuration
@Profile("useMocks")
public class MockConfigurer {
@Bean
@Primary
public MyBean myBeanSpy() {
return mock(MyBean.class);
}
}
Run Code Online (Sandbox Code Playgroud)
@Primary
如果没有指定限定符,则使用注释告诉spring该bean具有优先级.
确保您注释该类@Profile("useMocks")
以控制哪些类将使用模拟以及哪些将使用真实bean.
最后,在您的测试中,激活userMocks
配置文件:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
@ActiveProfiles(profiles={"useMocks"})
public class YourIntegrationTestIT {
@Inject
private MyBean myBean; //It will be the mock!
@Test
public void test() {
....
}
}
Run Code Online (Sandbox Code Playgroud)
如果你不想使用mock而不是真正的bean,那就不要激活useMocks
profile:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
public class AnotherIntegrationTestIT {
@Inject
private MyBean myBean; //It will be the real implementation!
@Test
public void test() {
....
}
}
Run Code Online (Sandbox Code Playgroud)
Dou*_*rop 19
由于1.8.3 Mockito有@InjectMocks - 这非常有用.我的JUnit测试是@RunWith MockitoJUnitRunner,我构建的@Mock对象满足所测试类的所有依赖关系,这些对象都是在私有成员使用@InjectMocks注释时注入的.
我@Run只使用SpringJUnit4Runner进行集成测试.
我会注意到它似乎无法以与Spring相同的方式注入List.它只查找满足List的Mock对象,并且不会注入Mock对象列表.我的解决方法是对手动实例化的列表使用@Spy,并手动.将模拟对象添加到该列表以进行单元测试.也许这是故意的,因为它肯定迫使我密切注意被嘲弄的东西.
tea*_*bot 13
更新:现在有更好,更清洁的解决方案来解决这个问题.请先考虑其他答案.
我终于在他的博客上找到了ronen的回答.我遇到的问题是由于Mockito.mock(Class c)
声明返回类型的方法Object
.因此Spring无法从工厂方法返回类型推断bean类型.
Ronen的解决方案是创建一个FactoryBean
返回模拟的实现.该FactoryBean
接口允许Spring查询工厂bean创建的对象类型.
我的模拟bean定义现在看起来像:
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>
Run Code Online (Sandbox Code Playgroud)
Rya*_*lls 12
从Spring 3.2开始,这不再是一个问题.Spring现在支持自动装配通用工厂方法的结果.请参阅此博客文章中标题为"通用工厂方法"的部分:http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/.
关键点是:
在Spring 3.2中,现在可以正确推断出工厂方法的泛型返回类型,并且按类型自动装配模拟应该按预期工作.因此,可能不再需要自定义解决方法,如MockitoFactoryBean,EasyMockFactoryBean或Springockito.
这意味着这应该是开箱即用的:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
Run Code Online (Sandbox Code Playgroud)
如果您使用的是spring> = 3.0,请尝试使用Springs @Configuration
注释来定义应用程序上下文的一部分
@Configuration
@ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {
@Bean
public ApplicationService applicationService() {
return mock(ApplicationService.class);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您不想使用@ImportResource,也可以通过其他方式完成:
<beans>
<!-- rest of your config -->
<!-- the container recognize this as a Configuration and adds it's beans
to the container -->
<bean class="com.package.DaoTestConfiguration"/>
</beans>
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请查看spring-framework-reference:基于Java的容器配置
小智 9
下面的代码适用于自动装配 - 它不是最短的版本,但它只适用于标准的spring/mockito jar时很有用.
<bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
<property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
</bean>
Run Code Online (Sandbox Code Playgroud)
也许不是完美的解决方案,但我倾向于不使用弹簧来进行单元测试.单个bean(被测试的类)的依赖关系通常不会过于复杂,所以我只是直接在测试代码中进行注入.
小智 7
我可以使用Mockito执行以下操作:
<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.abcd.StateMachine"/>
</bean>
Run Code Online (Sandbox Code Playgroud)
小智 6
基于上述方法发布一些示例
随着春天:
@ContextConfiguration(locations = { "classpath:context.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class TestServiceTest {
@InjectMocks
private TestService testService;
@Mock
private TestService2 testService2;
}
Run Code Online (Sandbox Code Playgroud)
没有春天:
@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
@InjectMocks
private TestService testService = new TestServiceImpl();
@Mock
private TestService2 testService2;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
232143 次 |
最近记录: |