使用弹簧豆的 JUnit 规则

2022-09-04 22:51:53

我有一个加载测试弹簧应用程序上下文的测试类,现在我想创建一个 junit 规则,它将在 mongo db 中设置一些测试数据。为此,我创建了一个规则类。

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

现在,我在我的测试类中使用此规则,并通过了 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 传递。有没有办法让规则在加载上下文后运行?


答案 1

据我所知,你试图实现的目标不可能以如此直接的方式实现,因为:

  1. 该规则在Spring的应用程序上下文之前实例化。
  2. SpringJUnit4ClassRunner不会尝试在规则的实例上注入任何东西。

这里描述了一个替代方案:https://blog.jayway.com/2014/12/07/junit-rule-spring-caches/ 但我认为在可以加载到mongodb中的内容方面,它是不够的。

为了实现您想要实现的目标,您可能需要一个测试执行侦听器,该侦听器将注入您在规则对象上所需的任何依赖项。


答案 2

下面是一个解决方案,使用一些抽象的超类:

@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";
    };

    // ...
}

推荐