JUnit rule using spring bean

I have a test class that loads the test context of a spring application, now I want to create a junit rule that will set some test data in mongo db. To do this, I created a rule 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); }); } } 

Now I use this rule inside my test class and pass the 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"); .... } 

The problem is that Rule is started before the application context is loaded, so the mongoOperations reference is passed as null. Is there a way to make the rules run after the context loads?

+5
source share
2 answers

Here's a solution using some abstract superclass:

 @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(); } 

then

 public class TransactionResourceTest extends AbstractTransactionResourceTest<PaymentInstrument> { @Override protected String entityName() { return "paymentInstrument"; }; // ... } 
+1
source

As far as I know, what are you trying to achieve, it is impossible in such a direct way, because:

  • the rule is created earlier by the Spring Application Context.
  • SpringJUnit4ClassRunner will not try to inject anything into the rule instance.

There is an alternative described here: https://blog.jayway.com/2014/12/07/junit-rule-spring-caches/ , but I think it will be short in terms of what can be downloaded in mongodb.

To achieve what you want to achieve, you probably need a test run listener that will inject any dependencies that you need into your rule object.

+2
source

All Articles