使用 spring bean 的 JUnit 规则
JUnit Rule using a spring bean
我有一个测试 class,它加载了一个测试 spring 应用程序上下文,现在我想创建一个 junit 规则,它将在 mongo 数据库中设置一些测试数据。为此,我创建了一个规则 class。
public class MongoRule<T> extends ExternalResource {
private MongoOperations mongoOperations;
private final String collectionName;
private final String file;
public MongoRule(MongoOperations mongoOperations, String file, String collectionName) {
this.mongoOperations = mongoOperations;
this.file = file;
this.collectionName = collectionName;
}
@Override
protected void before() throws Throwable {
String entitiesStr = FileUtils.getFileAsString(file);
List<T> entities = new ObjectMapper().readValue(entitiesStr, new TypeReference<List<T>>() {
});
entities.forEach((t) -> {
mongoOperations.save(t, collectionName);
});
}
}
现在我在我的测试中使用这个规则 class 并传递 mongoOperations bean。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringTestConfiguration.class)
public class TransactionResourceTest {
@Autowired
private ITransactionResource transactionResource;
@Autowired
private MongoOperations mongoOperations;
@Rule
public MongoRule<PaymentInstrument> paymentInstrumentMongoRule
= new MongoRule(mongoOperations, "paymentInstrument.js", "paymentInstrument");
....
}
问题是在加载应用程序上下文之前执行规则,因此 mongoOperations 引用作为 null 传递。有没有办法在加载上下文后制定规则运行?
这是一个解决方案,使用一些抽象的超级 class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringTestConfiguration.class)
public abstract class AbstractTransactionResourceTest<T> {
@Autowired
private ITransactionResource transactionResource;
@Autowired
private MongoOperations mongoOperations;
@Before
public void setUpDb() {
String entitiesStr = FileUtils.getFileAsString(entityName() + ".js");
List<T> entities = new ObjectMapper().readValue(entitiesStr, new TypeReference<List<T>>() {});
entities.forEach((t) -> {
mongoOperations.save(t, entityName());
});
}
protected abstract String entityName();
}
然后
public class TransactionResourceTest extends AbstractTransactionResourceTest<PaymentInstrument> {
@Override
protected String entityName() {
return "paymentInstrument";
};
// ...
}
据我所知,你想要实现的目标不可能以如此直接的方式实现,因为:
- 规则在 Spring 的应用程序上下文之前实例化。
- SpringJUnit4ClassRunner 不会尝试在规则的实例上注入任何内容。
此处描述了另一种选择:https://blog.jayway.com/2014/12/07/junit-rule-spring-caches/,但我认为就可以加载到 mongodb 中的内容而言,它会有所不足。
为了实现您想要实现的目标,您可能需要一个测试执行侦听器,它会在您的规则对象上注入您需要的任何依赖项。
我有一个测试 class,它加载了一个测试 spring 应用程序上下文,现在我想创建一个 junit 规则,它将在 mongo 数据库中设置一些测试数据。为此,我创建了一个规则 class。
public class MongoRule<T> extends ExternalResource {
private MongoOperations mongoOperations;
private final String collectionName;
private final String file;
public MongoRule(MongoOperations mongoOperations, String file, String collectionName) {
this.mongoOperations = mongoOperations;
this.file = file;
this.collectionName = collectionName;
}
@Override
protected void before() throws Throwable {
String entitiesStr = FileUtils.getFileAsString(file);
List<T> entities = new ObjectMapper().readValue(entitiesStr, new TypeReference<List<T>>() {
});
entities.forEach((t) -> {
mongoOperations.save(t, collectionName);
});
}
}
现在我在我的测试中使用这个规则 class 并传递 mongoOperations bean。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringTestConfiguration.class)
public class TransactionResourceTest {
@Autowired
private ITransactionResource transactionResource;
@Autowired
private MongoOperations mongoOperations;
@Rule
public MongoRule<PaymentInstrument> paymentInstrumentMongoRule
= new MongoRule(mongoOperations, "paymentInstrument.js", "paymentInstrument");
....
}
问题是在加载应用程序上下文之前执行规则,因此 mongoOperations 引用作为 null 传递。有没有办法在加载上下文后制定规则运行?
这是一个解决方案,使用一些抽象的超级 class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringTestConfiguration.class)
public abstract class AbstractTransactionResourceTest<T> {
@Autowired
private ITransactionResource transactionResource;
@Autowired
private MongoOperations mongoOperations;
@Before
public void setUpDb() {
String entitiesStr = FileUtils.getFileAsString(entityName() + ".js");
List<T> entities = new ObjectMapper().readValue(entitiesStr, new TypeReference<List<T>>() {});
entities.forEach((t) -> {
mongoOperations.save(t, entityName());
});
}
protected abstract String entityName();
}
然后
public class TransactionResourceTest extends AbstractTransactionResourceTest<PaymentInstrument> {
@Override
protected String entityName() {
return "paymentInstrument";
};
// ...
}
据我所知,你想要实现的目标不可能以如此直接的方式实现,因为:
- 规则在 Spring 的应用程序上下文之前实例化。
- SpringJUnit4ClassRunner 不会尝试在规则的实例上注入任何内容。
此处描述了另一种选择:https://blog.jayway.com/2014/12/07/junit-rule-spring-caches/,但我认为就可以加载到 mongodb 中的内容而言,它会有所不足。
为了实现您想要实现的目标,您可能需要一个测试执行侦听器,它会在您的规则对象上注入您需要的任何依赖项。