【问题标题】:JUnit Rule using a spring bean使用 spring bean 的 JUnit 规则
【发布时间】:2016-07-28 04:34:25
【问题描述】:

我有一个加载测试 spring 应用程序上下文的测试类,现在我想创建一个 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");    
....
}

问题是 Rule 在应用程序上下文加载之前被执行,所以 mongoOperations 引用作为 null 传递。有没有办法让规则在上下文加载后运行?

【问题讨论】:

    标签: java junit spring-junit


    【解决方案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";
          };
      
          // ...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-01
        • 2011-07-05
        • 2017-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-06
        • 1970-01-01
        相关资源
        最近更新 更多