How to run JUnit SpringJUnit4ClassRunner with Parametrized?

后端 未结 4 1232
被撕碎了的回忆
被撕碎了的回忆 2020-12-12 16:16

The following code is invalid due to duplicate @RunWith annotation:

@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(Parameterized.class)
@Sprin         


        
相关标签:
4条回答
  • 2020-12-12 16:43

    You can use SpringClassRule and SpringMethodRule - supplied with Spring

    import org.junit.ClassRule;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.springframework.test.context.junit4.rules.SpringClassRule;
    import org.springframework.test.context.junit4.rules.SpringMethodRule;
    
    @RunWith(Parameterized.class)
    @ContextConfiguration(...)
    public class MyTest {
    
        @ClassRule
        public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
    
        @Rule
        public final SpringMethodRule springMethodRule = new SpringMethodRule();
    
        ...
    
    0 讨论(0)
  • 2020-12-12 16:46

    There is another solution with JUnit 4.12 without the need of Spring 4.2+.

    JUnit 4.12 introduces ParametersRunnerFactory which allow to combine parameterized test and Spring injection.

    public class SpringParametersRunnerFactory implements ParametersRunnerFactory {
    @Override
      public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
        final BlockJUnit4ClassRunnerWithParameters runnerWithParameters = new BlockJUnit4ClassRunnerWithParameters(test);
        return new SpringJUnit4ClassRunner(test.getTestClass().getJavaClass()) {
          @Override
          protected Object createTest() throws Exception {
            final Object testInstance = runnerWithParameters.createTest();
            getTestContextManager().prepareTestInstance(testInstance);
            return testInstance;
          }
        };
      }
    }
    

    The factory can be added to test class to give full Spring support like test transaction, reinit dirty context and servlet test.

    @UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
    @RunWith(Parameterized.class)
    @ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
    @WebAppConfiguration
    @Transactional
    @TransactionConfiguration
    public class MyTransactionalTest {
    
      @Autowired
      private WebApplicationContext context;
    
      ...
    }
    

    If you need Spring context inside @Parameters static method to provide parameters to test instances, please see my answer here How can I use the Parameterized JUnit test runner with a field that's injected using Spring?.

    0 讨论(0)
  • 2020-12-12 16:49

    Handle application context by yourself

    What worked for me was having a @RunWith(Parameterized.class) test class that managed the application context "by hand".

    To do that I created an application context with the same string collection that would be in the @ContextConfiguration. So instead of having

    @ContextConfiguration(locations = { "classpath:spring-config-file1.xml",
        "classpath:spring-config-file2.xml" })
    

    I had

    ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {
                "classpath:spring-config-file1.xml", "classpath:spring-config-file2.xml"  });
    

    And for each @Autowired I needed I fetched it by hand from the created context:

    SomeClass someBean = ctx.getBean("someClassAutowiredBean", SomeClass.class);
    

    Do not forget to close the context at the end:

    ((ClassPathXmlApplicationContext) ctx).close();
    
    0 讨论(0)
  • 2020-12-12 16:55

    There are at least 2 options to do that:

    1. Following http://www.blog.project13.pl/index.php/coding/1077/runwith-junit4-with-both-springjunit4classrunner-and-parameterized/

      Your test needs to look something like this:

       @RunWith(Parameterized.class)
       @ContextConfiguration(classes = {ApplicationConfigTest.class})
       public class ServiceTest {
      
           private TestContextManager testContextManager;
      
           @Before
           public void setUpContext() throws Exception {
               //this is where the magic happens, we actually do "by hand" what the spring runner would do for us,
              // read the JavaDoc for the class bellow to know exactly what it does, the method names are quite accurate though
             this.testContextManager = new TestContextManager(getClass());
             this.testContextManager.prepareTestInstance(this);
           }
           ...
       }
      
    2. There is a github project https://github.com/mmichaelis/spring-aware-rule, which builds on previous blog, but adds support in a generalized way

      @SuppressWarnings("InstanceMethodNamingConvention")
      @ContextConfiguration(classes = {ServiceTest.class})
      public class SpringAwareTest {
      
          @ClassRule
          public static final SpringAware SPRING_AWARE = SpringAware.forClass(SpringAwareTest.class);
      
          @Rule
          public TestRule springAwareMethod = SPRING_AWARE.forInstance(this);
      
          @Rule
          public TestName testName = new TestName();
      
          ...
      }
      

    So you can have a basic class implementing one of the approaches, and all tests inheriting from it.

    0 讨论(0)
提交回复
热议问题