Chapter 7: 测试
我们先写一个简单的@Configuration:
然后看是否能够正确地注册Bean:
private AnnotationConfigApplicationContext context;
@BeforeMethod
public void init() {
context = new AnnotationConfigApplicationContext();
}
@AfterMethod(alwaysRun = true)
public void reset() {
context.close();
}
@Test
public void testFooCreation() {
context.register(FooConfiguration.class);
context.refresh();
assertNotNull(context.getBean(Foo.class));
}
}
注意上面代码中关于Context的代码:
- 首先,我们构造一个Context
- 然后,注册FooConfiguration
- 然后,refresh Context
- 最后,在测试方法结尾close Context
如果你看Spring Boot中关于@Configuration测试的源代码会发现和上面的代码有点不一样:
public class DataSourceAutoConfigurationTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Before
public void init() {
EmbeddedDatabaseConnection.override = null;
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false",
"spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt());
}
@After
public void restore() {
EmbeddedDatabaseConnection.override = null;
this.context.close();
}
这是因为Spring和Spring Boot都是用JUnit做测试的,而JUnit的特性是每次执行测试方法前,都会new一个测试类实例,而TestNG是在共享同一个测试类实例的。
Spring Framework提供了一种可以条件控制的机制,即只在满足某条件的情况下才会导入@Configuration,这就是。
该Condition判断Environment中是否有foo.create=true
。
如果我们要测试这个Condition,那么就必须往Environment里添加相关property才可以,在这里我们测试了三种情况:
- 没有配置
foo.create=true
- 配置
foo.create=true
- 配置
foo.create=false
:
public class FooConfigurationTest {
@BeforeMethod
public void init() {
context = new AnnotationConfigApplicationContext();
@AfterMethod(alwaysRun = true)
public void reset() {
context.close();
}
@Test(expectedExceptions = NoSuchBeanDefinitionException.class)
public void testFooCreatePropertyNull() {
context.register(FooConfiguration.class);
context.refresh();
context.getBean(Foo.class);
}
@Test
public void testFooCreatePropertyTrue() {
context.getEnvironment().getPropertySources().addLast(
new MapPropertySource("test", Collections.singletonMap("foo.create", "true"))
);
context.register(FooConfiguration.class);
context.refresh();
assertNotNull(context.getBean(Foo.class));
}
@Test(expectedExceptions = NoSuchBeanDefinitionException.class)
public void testFooCreatePropertyFalse() {
context.getEnvironment().getPropertySources().addLast(
new MapPropertySource("test", Collections.singletonMap("foo.create", "false"))
);
context.register(FooConfiguration.class);
context.refresh();
assertNotNull(context.getBean(Foo.class));
}
}
注意我们用以下方法来给Environment添加property:
context.getEnvironment().getPropertySources().addLast(
new MapPropertySource("test", Collections.singletonMap("foo.create", "true"))
);
所以针对@Conditional和其对应的Condition的测试的根本就是给它不一样的条件,判断其行为是否正确,在这个例子里我们的Condition比较简单,只是判断是否存在某个property,如果复杂Condition的话,测试思路也是一样的。
Spring framework只提供了@Conditional,Spring boot对这个机制做了扩展,提供了更为丰富的,这里我们以@ConditionalOnProperty举例说明。
:
public class FooConfigurationTest {
private AnnotationConfigApplicationContext context;
@BeforeMethod
public void init() {
context = new AnnotationConfigApplicationContext();
}
@AfterMethod(alwaysRun = true)
public void reset() {
@Test(expectedExceptions = NoSuchBeanDefinitionException.class)
public void testFooCreatePropertyNull() {
context.register(FooConfiguration.class);
context.refresh();
context.getBean(Foo.class);
}
@Test
public void testFooCreatePropertyTrue() {
EnvironmentTestUtils.addEnvironment(context, "foo.create=true");
context.register(FooConfiguration.class);
context.refresh();
assertNotNull(context.getBean(Foo.class));
}
@Test(expectedExceptions = NoSuchBeanDefinitionException.class)
public void testFooCreatePropertyFalse() {
EnvironmentTestUtils.addEnvironment(context, "foo.create=false");
context.register(FooConfiguration.class);
context.refresh();
assertNotNull(context.getBean(Foo.class));
}
}
这段测试代码和例子2的逻辑差不多,只不过例子2里使用了我们自己写的Condition,这里使用了Spring Boot提供的@ConditionalOnProperty。
并且利用了Spring Boot提供的简化了给Environment添加property的工作:
EnvironmentTestUtils.addEnvironment(context, "foo.create=false");
Spring Boot还提供了类型安全的Configuration Properties,下面举例如何对其进行测试。
:
public class BarConfigurationTest {
private AnnotationConfigApplicationContext context;
@BeforeMethod
public void init() {
context = new AnnotationConfigApplicationContext();
}
@AfterMethod(alwaysRun = true)
public void reset() {
context.close();
}
@Test
public void testBarCreation() {
EnvironmentTestUtils.addEnvironment(context, "bar.name=test");
context.register(BarConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
context.refresh();
assertEquals(context.getBean(Bar.class).getName(), "test");
}
}