junit规则
介绍
在本文中,我想展示一个示例,说明如何使用JUnit Rule简化测试。
最近,我继承了一个相当复杂的系统,并未对所有内容进行测试。 甚至经过测试的代码也很复杂。 通常,我看到缺乏测试隔离。 (我将写一个关于使用Legacy Code的不同博客)。
我正在修复的测试(和代码)之一实际上是将多个组件一起测试。 它还连接到数据库。 它测试一些逻辑和组件之间的交集。 如果代码没有在完全不同的位置编译,则测试无法运行,因为它加载了所有Spring上下文。 其结构是在测试(任何类)之前启动所有Spring上下文。 这些测试扩展了BaseTest,该加载了所有Spring上下文。
BaseTest还使用@After方法清除数据库。
重要说明:本文是关于更改测试的,并非结构完全正确。 在创建新代码和测试时,应该将它们隔离,一事不做。更好的测试应该使用模拟数据库/依赖项等。修复测试和重构后,我将充满信心进行更多更改。
回到我们的话题…
因此,我得到的是测试套件运行缓慢,没有隔离,甚至由于不相关的问题而导致测试运行出现问题。 因此,我决定将数据库连接的上下文加载与清理数据库分开。
方法
为了实现这一点,我做了三件事:首先是更改测试类的继承。 它停止继承BaseTest。 相反,它继承了AbstractJUnit4SpringContextTests现在,我可以为每个测试创建自己的上下文,而不加载所有内容。
现在我需要两个规则,@ClassRule和@Rule @ClassRule将负责数据库连接@Rule将在每次测试之后/之前清理数据库。
但是首先, 什么是JUnit规则?
简短的解释是,它们提供了拦截测试方法的可能性,类似于AOP概念。 @Rule允许我们在方法实际运行之前和之后拦截方法。 @ClassRule拦截测试类的运行。 一个非常有名的@Rule是JUnit的TemporaryFolder 。
(类似于@ Before,@ After和@BeforeClass)。
创建@Rule
最简单的部分是创建一个在测试方法之前和之后清理数据库的规则。 您需要实现TestRule ,它具有一种方法: 语句apply(Statement base,Description description); 你可以做很多。 我发现通常我会有一个扩展Statement的内部类。 我创建的规则并未创建数据库连接,而是在构造函数中获得了它。
这是完整的代码:
public class DbCleanupRule implements TestRule {
private final DbConnectionManager connection;
public MongoCleanupRule(DbConnectionManager connection) {
this.connection = connection;
}
@Override
public Statement apply(Statement base, Description description) {
return new MongoCleanupStatement(base, connection);
}
private static final class DbCleanupStatement extends Statement {
private final Statement base;
private final DbConnectionManager connection;
private MongoCleanupStatement(Statement base, DbConnectionManager connection) {
this.base = base;
this.connection = connection;
}
@Override
public void evaluate() throws Throwable {
try {
cleanDb();
base.evaluate();
} finally {
cleanDb();
}
}
private void cleanDb() {
connection.doTheCleanup();
}
}
}
创建@ClassRule
ClassRule实际上也是TestRule。 与Rule的唯一区别是我们在测试代码中如何使用它。 我将在下面显示。
创建此规则的挑战在于,我想使用Spring上下文来获取正确的连接。
这是代码:
(ExternalResource是TestRule)
public class DbConnectionRule extends ExternalResource {
private DbConnectionManager connection;
public DbConnectionRule() {
}
@Override
protected void before() throws Throwable {
ClassPathXmlApplicationContext ctx = null;
try {
ctx = new ClassPathXmlApplicationContext("/META-INF/my-db-connection-TEST-ctx.xml");
mongoDb = (DbConnectionManager) ctx.getBean("myDbConnection");
} finally {
if (ctx != null) {
ctx.close();
}
}
}
@Override
protected void after() {
}
public DbConnectionManager getDbConnecttion() {
return connection;
}
}
(您是否看到我可以使DbCleanupRule继承ExternalResource?)
使用它
最后一部分是我们如何使用规则。 @Rule必须是公共字段。 @ClassRule必须是公共静态字段。
那里是:
@ContextConfiguration(locations = { "/META-INF/one-dao-TEST-ctx.xml", "/META-INF/two-TEST-ctx.xml" })
public class ExampleDaoTest extends AbstractJUnit4SpringContextTests {
@ClassRule
public static DbCleanupRule connectionRule = new DbCleanupRule ();
@Rule
public DbCleanupRule dbCleanupRule = new DbCleanupRule(connectionRule.getDbConnecttion());
@Autowired
private ExampleDao classToTest;
@Test
public void foo() {
}
}
就这样。
希望能帮助到你。
翻译自: https://www.javacodegeeks.com/2014/09/junit-rules-3.html
junit规则