运行 针对两个不同的注入依赖项进行单元测试
Run unit tests against two different injected dependencies
我的应用程序中有两个服务 bean,它们都实现了一个接口。对于该接口,所有方法都必须执行相同的操作(内部结构不同)。
所以我想编写一组针对这两种服务运行的测试。 (不想写重复代码)
构建我的测试以实现此目的的最佳方式是什么?
(我标记了 junit4,因为这是我目前限制的版本。)
您可以在 JavaConfig 中创建一个包含实现列表的 bean:
public class TestConfig {
@Bean
MyService myService1(){
return new MyService1();
}
@Bean
MyService myService2(){
return new MyService2();
}
@Bean
public List<MyService> myServices(MyService myService1, MyService myService2){
List<MyService> allServices = new ArrayList<>();
allServices.add(myService1);
allServices.add(myService2);
return allServices;
}
}
并最终在您的测试中迭代此列表:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=TestConfig.class)
public class ServicesTest {
@Autowired
private List<MyService> allServices;
@Test
public void testAllServices(){
for (MyService service : allServices) {
// Test service here
}
}
}
几个选项:
您可以将所有 classes 存储在常量中,例如 List<Class<? extends YourInterface>> classes = Arrays.asList(Implementation.class)
循环遍历这些 classes 并为每个
[调用方法=20=]
您可以使用 Reflections 找到所有实现特定接口的 classes 并为每个 class.
循环
您可以有一个自动装配的服务列表,并按照某些人的建议循环遍历并测试每个实现。但我想说这实际上不是一个很好的解决方案,原因有很多:
- 如果任何一个实现失败,那么另一个实现可能被破坏,你不会知道,直到你 运行 再次测试并修复错误
- 最好进行更多非常简单的测试,而不是进行更多的测试,因为这样会更难追踪故障。
- 需要 Spring - 这一点可能无关紧要,但如果至少减少正在测试的系统数量,不依赖所有这些结构可能是有利的
您可能会喜欢类型参数并从通用基础 class 继承,例如 class BaseTest<HW extends HelloWorldInterface >
和 @Autowired HW hw
,然后简单地使用 class 扩展此 class =13=] 其中 GutenTag implements HelloWorldInterface
.
但是我试过了,我发现简单地针对接口编写断言函数更简单,如下所示:
public static void assertImplementationSaysHelloWorld(HelloWorldInterface hello, String expectedResult) {
assertEquals(expectedResult, hello);
}
发生的事情少得多,而且该功能比继承更可重用。例如,如果我有一个 class 实现了多个接口,使用继承方法我将被迫编写更多 classes 来测试每个接口。而我可以在一次测试中使用任意多个不同的断言函数 class.
这里的其他答案都很好,但不完全符合我的喜好。
我最终结合了
- JUnit 的
@RunWith(@Parameterized)
(运行 两种服务的测试)
- Spring 的新规则(保留
@RunWith(SpringRunner.class)
容器、appcontext、webmvc 和注入功能)
以下是片段:
@RunWith(Parameterized.class)
...
@Parameters(name = "Cached = {0}")
public static Boolean[] data() {
return new Boolean[] { Boolean.TRUE, Boolean.FALSE };
}
@ClassRule
public static final SpringClassRule springClassRule = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Before
public void setUp() {
// logic to choose the injected service based on the true/false param
}
我的应用程序中有两个服务 bean,它们都实现了一个接口。对于该接口,所有方法都必须执行相同的操作(内部结构不同)。
所以我想编写一组针对这两种服务运行的测试。 (不想写重复代码)
构建我的测试以实现此目的的最佳方式是什么?
(我标记了 junit4,因为这是我目前限制的版本。)
您可以在 JavaConfig 中创建一个包含实现列表的 bean:
public class TestConfig {
@Bean
MyService myService1(){
return new MyService1();
}
@Bean
MyService myService2(){
return new MyService2();
}
@Bean
public List<MyService> myServices(MyService myService1, MyService myService2){
List<MyService> allServices = new ArrayList<>();
allServices.add(myService1);
allServices.add(myService2);
return allServices;
}
}
并最终在您的测试中迭代此列表:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=TestConfig.class)
public class ServicesTest {
@Autowired
private List<MyService> allServices;
@Test
public void testAllServices(){
for (MyService service : allServices) {
// Test service here
}
}
}
几个选项:
您可以将所有 classes 存储在常量中,例如
[调用方法=20=]List<Class<? extends YourInterface>> classes = Arrays.asList(Implementation.class)
循环遍历这些 classes 并为每个您可以使用 Reflections 找到所有实现特定接口的 classes 并为每个 class.
循环
您可以有一个自动装配的服务列表,并按照某些人的建议循环遍历并测试每个实现。但我想说这实际上不是一个很好的解决方案,原因有很多:
- 如果任何一个实现失败,那么另一个实现可能被破坏,你不会知道,直到你 运行 再次测试并修复错误
- 最好进行更多非常简单的测试,而不是进行更多的测试,因为这样会更难追踪故障。
- 需要 Spring - 这一点可能无关紧要,但如果至少减少正在测试的系统数量,不依赖所有这些结构可能是有利的
您可能会喜欢类型参数并从通用基础 class 继承,例如 class BaseTest<HW extends HelloWorldInterface >
和 @Autowired HW hw
,然后简单地使用 class 扩展此 class =13=] 其中 GutenTag implements HelloWorldInterface
.
但是我试过了,我发现简单地针对接口编写断言函数更简单,如下所示:
public static void assertImplementationSaysHelloWorld(HelloWorldInterface hello, String expectedResult) {
assertEquals(expectedResult, hello);
}
发生的事情少得多,而且该功能比继承更可重用。例如,如果我有一个 class 实现了多个接口,使用继承方法我将被迫编写更多 classes 来测试每个接口。而我可以在一次测试中使用任意多个不同的断言函数 class.
这里的其他答案都很好,但不完全符合我的喜好。 我最终结合了
- JUnit 的
@RunWith(@Parameterized)
(运行 两种服务的测试) - Spring 的新规则(保留
@RunWith(SpringRunner.class)
容器、appcontext、webmvc 和注入功能)
以下是片段:
@RunWith(Parameterized.class)
...
@Parameters(name = "Cached = {0}")
public static Boolean[] data() {
return new Boolean[] { Boolean.TRUE, Boolean.FALSE };
}
@ClassRule
public static final SpringClassRule springClassRule = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Before
public void setUp() {
// logic to choose the injected service based on the true/false param
}