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

时间:2010-03-23 19:08:54

标签: java spring junit

有没有办法让一个扩展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
    }
}

7 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:4)

您可以使用Spring的TestContextManager。在这个例子中,我使用Theories而不是Parameterized。

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

我在这里找到了这个解决方案:How to do Parameterized/Theories tests with Spring

答案 2 :(得分:1)

不,你不能。超类有:

@RunWith(SpringJUnit4ClassRunner.class)

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

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

答案 3 :(得分:0)

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

}

这是full example

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

答案 4 :(得分:0)

我必须以编程方式处理交易(请参阅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;
            }
        });

    }

答案 5 :(得分:0)

您可以将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
    }
}

答案 6 :(得分:0)

这是我在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,该方法将返回一个Collection,该Collection包含每次迭代中您的参数值,并遵守将它们传递给构造函数的顺序:

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