使用 ServiceLocatorFactoryBean Autowired 对 class 进行单元测试
Unit Testing a class with ServiceLocatorFactoryBean Autowired
我有一个注册为 ServiceLocatorFactoryBean 一部分的接口。这个接口的主要目的是作为一个工厂。
我在各种 class 中有 "autowired" 这个接口,我现在想用 Mockito 测试它。
问题是 Mockito 不支持接口。如何在我正在测试的 class 中注入此接口的模拟。
我看到的唯一选择是 运行 使用 SpringJunitRunner 并提供具有 bean 配置的应用程序上下文的测试。但这太冗长了。
我猜你想监视 Spring 为你的界面生成的实现?!到目前为止,这几乎是不可能实现的……但是至少有以下替代方案。
假设我们有以下设置:
public interface MyService {
String doIt();
}
@Component
public static class ServiceConsumer {
@Autowired
private MyService service;
public String execute() {
return service.doIt();
}
}
0) 稍后编辑: 而 roaming around, I found that it may be possible to spy and even replace an autowired field with a mock, and fairly easy too, using Springockito-annotations.
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan
@ContextConfiguration(loader = SpringockitoAnnotatedContextLoader.class, classes = {SpringockitoConsumerTest.class})
public class SpringockitoConsumerTest {
@WrapWithSpy(beanName = "myService")
@Autowired
private MyService mockService;
@Autowired
private ServiceConsumer consumer;
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(mockService).doIt();
}
}
如果Springockito-annotations
不对,请看下面2条原创建议
1) 您可以只创建您的接口模拟并将其自动注入您的 bean 中的 Mockito。这是最简单的解决方案(我在撰写本文时能想到)但它不能确保 @Autowired
注释不会在消费者中被遗忘(也许可以添加专门的测试?!):
public class AutoInjectMocksConsumerTest {
@Mock
private MyService serviceMock;
@InjectMocks
private ServiceConsumer consumer = new ServiceConsumer();
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
when(serviceMock.doIt()).thenReturn("allDone");
}
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(serviceMock).doIt();
}
}
2) 或者正如您所说,您可以 运行 它与 SpringJunitRunner
一起定义和实例化必要的 [= =45=] 上下文,同时还提供您自己的服务模拟。尽管人们可能会抱怨这个解决方案 不是那么干净 ,但我发现它足够优雅并且它还验证了 @Autowired
注释在消费者实现中没有被遗忘。
@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
@ComponentScan
@ContextConfiguration(classes = {SpringAutowiringConsumerTest.class})
public class SpringAutowiringConsumerTest {
@Autowired
private MyService mockService;
@Autowired
private ServiceConsumer consumer;
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(mockService).doIt();
}
@Bean
public MyService mockService() {
MyService serviceMock = mock(MyService.class);
when(serviceMock.doIt()).thenReturn("allDone");
return serviceMock;
}
}
我有一个注册为 ServiceLocatorFactoryBean 一部分的接口。这个接口的主要目的是作为一个工厂。
我在各种 class 中有 "autowired" 这个接口,我现在想用 Mockito 测试它。
问题是 Mockito 不支持接口。如何在我正在测试的 class 中注入此接口的模拟。
我看到的唯一选择是 运行 使用 SpringJunitRunner 并提供具有 bean 配置的应用程序上下文的测试。但这太冗长了。
我猜你想监视 Spring 为你的界面生成的实现?!到目前为止,这几乎是不可能实现的……但是至少有以下替代方案。
假设我们有以下设置:
public interface MyService {
String doIt();
}
@Component
public static class ServiceConsumer {
@Autowired
private MyService service;
public String execute() {
return service.doIt();
}
}
0) 稍后编辑: 而 roaming around, I found that it may be possible to spy and even replace an autowired field with a mock, and fairly easy too, using Springockito-annotations.
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan
@ContextConfiguration(loader = SpringockitoAnnotatedContextLoader.class, classes = {SpringockitoConsumerTest.class})
public class SpringockitoConsumerTest {
@WrapWithSpy(beanName = "myService")
@Autowired
private MyService mockService;
@Autowired
private ServiceConsumer consumer;
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(mockService).doIt();
}
}
如果Springockito-annotations
不对,请看下面2条原创建议
1) 您可以只创建您的接口模拟并将其自动注入您的 bean 中的 Mockito。这是最简单的解决方案(我在撰写本文时能想到)但它不能确保 @Autowired
注释不会在消费者中被遗忘(也许可以添加专门的测试?!):
public class AutoInjectMocksConsumerTest {
@Mock
private MyService serviceMock;
@InjectMocks
private ServiceConsumer consumer = new ServiceConsumer();
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
when(serviceMock.doIt()).thenReturn("allDone");
}
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(serviceMock).doIt();
}
}
2) 或者正如您所说,您可以 运行 它与 SpringJunitRunner
一起定义和实例化必要的 [= =45=] 上下文,同时还提供您自己的服务模拟。尽管人们可能会抱怨这个解决方案 不是那么干净 ,但我发现它足够优雅并且它还验证了 @Autowired
注释在消费者实现中没有被遗忘。
@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
@ComponentScan
@ContextConfiguration(classes = {SpringAutowiringConsumerTest.class})
public class SpringAutowiringConsumerTest {
@Autowired
private MyService mockService;
@Autowired
private ServiceConsumer consumer;
@Test
public void shouldConsumeService() {
assertEquals("allDone", consumer.execute());
verify(mockService).doIt();
}
@Bean
public MyService mockService() {
MyService serviceMock = mock(MyService.class);
when(serviceMock.doIt()).thenReturn("allDone");
return serviceMock;
}
}