繁体   English   中英

Spring 事务参数化测试和自动装配

[英]Spring Transactional Parameterized Test and Autowiring

有没有办法让一个扩展 AbstractTransactionalJUnit4SpringContexts 的类与 JUnit 自己的 @RunWith(Parameterized.class) 很好地配合,以便标记为 Autowired 的字段正确连接?

@RunWith(Parameterized.class)
public class Foo extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired private Bar bar

    @Parameters public static Collection<Object[]> data() {
        // return parameters, following pattern in
        // http://junit.org/apidocs/org/junit/runners/Parameterized.html
    }

    @Test public void someTest(){
        bar.baz() //NullPointerException
    }
}

参见http://jira.springframework.org/browse/SPR-5292有一个解决方案。

您可以使用 Spring 中的 TestContextManager。 在这个例子中,我使用的是理论而不是参数化。

@RunWith(Theories.class)
@ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
  @DataPoints
  public static WebDriver[] drivers() {
    return new WebDriver[] { firefoxDriver, internetExplorerDriver };
  }

  private TestContextManager testContextManager;

  @Autowired
  SomethingDao dao;

  private static FirefoxDriver firefoxDriver = new FirefoxDriver();
  private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();

  @AfterClass
  public static void tearDown() {
    firefoxDriver.close();
    internetExplorerDriver.close();
  }

  @Before
  public void setUpStringContext() throws Exception {
    testContextManager = new TestContextManager(getClass());
    testContextManager.prepareTestInstance(this);
  }

  @Theory
  public void testWork(WebDriver driver) {
    assertNotNull(driver);
    assertNotNull(dao);
  }
}

我在这里找到了这个解决方案: 如何使用 Spring 进行参数化/理论测试

为此,您可以使用SpringClassRuleSpringMethodRule

@RunWith(Parameterized.class)
@ContextConfiguration(...)
public class FooTest {

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Autowired 
    private Bar bar

    @Parameters 
    public static Collection<Object[]> data() {
        // return parameters, following pattern in
        // http://junit.org/apidocs/org/junit/runners/Parameterized.html
    }

    @Test 
    public void someTest() {
        bar.baz() //NullPointerException
    }
}

不,你不能。 超类有:

@RunWith(SpringJUnit4ClassRunner.class)

这确保测试在 spring 上下文中运行。 如果你更换它,你就会失去这个。

我想到的替代方案是扩展SpringJunit4ClassRunner ,在那里提供您的自定义功能并将其与@RunWith(..) 因此,您将拥有 spring 上下文 + 您的附加功能。 它将调用super.createTest(..)然后在测试中执行其他内容。

以下是我在 Spring Boot 1.5.7

  1. @RunWith(Parameterized.class)注释添加到您的类

  2. 将您的依赖项作为类字段注入:

     @Autowired private Bar bar;
  3. 将您的参数添加为类字段:

     private final int qux; private final Boolean corge; private final String grault;
  4. 添加构造函数以初始化参数,如下所示:

     public Foo(int qux, Boolean corge, String grault) throws Exception { this.qux = qux; this.corge = corge; this.grault = grault; new TestContextManager(getClass()).prepareTestInstance(this); }
  5. 添加一个静态方法data ,它返回一个包含每次迭代时参数值的集合,尊重它们传递给构造函数的顺序:

     @Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][]{ { 1, Boolean.FALSE, "Hello" }, { 2, Boolean.TRUE, null }, { 3, null, "world" } }); }
  6. 使用上面声明的类字段编写您的测试,如下所示:

     @Test public void someTest(){ // Some arrangements // Some actions assertThat(myTestedIntValue, is(equalTo(qux)); assertThat(myTestedBooleanValue, is(equalTo(corge)); assertThat(myTestedStringValue, is(equalTo(grault)); }

我不得不以编程方式处理事务(参见http://www.javathinking.com/2011/09/junit-parameterized-test-with-spring-autowiring-and-transactions/ ):

@RunWith(Parameterized.class)
@ContextConfiguration(locations = "classpath*:/testContext.xml")
public class MyTest {

    @Autowired
    PlatformTransactionManager transactionManager;

    private TestContextManager testContextManager;

    public MyTest (... parameters for test) {
        // store parameters in instance variables
    }

    @Before
    public void setUpSpringContext() throws Exception {
        testContextManager = new TestContextManager(getClass());
        testContextManager.prepareTestInstance(this);
    }

    @Parameterized.Parameters
    public static Collection<Object[]> generateData() throws Exception {
        ArrayList list = new ArrayList();
        // add data for each test here
        return list;
    }

    @Test
    public void validDataShouldLoadFully() throws Exception {
        new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
            public Object doInTransaction(TransactionStatus status) {
                status.setRollbackOnly();
                try {
                    ... do cool stuff here

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return null;
            }
        });

    }

受 Simon 解决方案的启发,您还可以将 TestContextManager 与参数化运行程序一起使用:

@RunWith(Parameterized.class)
@ContextConfiguration(locations = "classpath:/spring-context.xml")
public class MyTestClass {

  @Parameters public static Collection data() {
    // return parameters, following pattern in
    // http://junit.org/apidocs/org/junit/runners/Parameterized.html
  }

  @Before
  public void setUp() throws Exception {
    new TestContextManager(getClass()).prepareTestInstance(this);
  }

}

这是完整的例子

在这种情况下,我不确定如何处理 @Transactional。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM