代码之家  ›  专栏  ›  技术社区  ›  Edward Dale

如何将参数化的JUnit测试运行程序与使用Spring注入的字段一起使用?

  •  18
  • Edward Dale  · 技术社区  · 15 年前

    我使用Spring将一个目录的路径注入到我的单元测试中。在这个目录中有一些文件应该用来为参数化测试用例生成测试数据,这些测试用例使用 Parameterized 测试转轮。不幸的是,测试运行程序要求提供参数的方法是静态的。这对我的情况不起作用,因为目录只能注入到非静态字段中。我有什么办法避开这个吗?

    7 回复  |  直到 7 年前
        1
  •  7
  •   Jeanne Boyarsky    15 年前

    我假设您使用的是JUnit4.x,因为您提到了参数化测试运行程序。这意味着您没有使用@runwith(springjunit4classrunner)。没问题,只是列出我的假设。

    下面使用Spring从XML文件获取测试文件目录。它不会注入它,但是数据仍然可以用于测试。在静态方法中也不例外。

    我看到的唯一缺点是,这可能意味着您的Spring配置被多次解析/配置。如果需要的话,您可以加载一个包含测试特定信息的小文件。

    @RunWith(Parameterized.class)
    public class MyTest {
        @Parameters
        public static Collection<Object[]> data() {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("/jeanne/jeanne.xml");
            String dir = ctx.getBean("testFilesDirectory", String.class);
    
                // write java code to link files in test directory to the array
            return Arrays.asList(new Object[][] { { 1 } });
        }
    // rest of test class
    }
    
        2
  •  11
  •   gnuf    14 年前

    可以使用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);
      }
    }
    

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

        3
  •  5
  •   secure_paul Abhijit Sarkar    9 年前

    对于2015年末或以后阅读的人来说, Spring 4.2 除了SpringJunit4ClassRunner之外,还添加了SpringClassRule和SpringMethodRule,它们利用对 Spring TestContext Framework .

    这意味着对任何类似跑步者的一流支持 MockitoJUnitRunner Parameterized :

    @RunWith(Parameterized.class)
    public class FibonacciTest {
        @ClassRule public static final SpringClassRule SCR = new SpringClassRule();
        @Rule public final SpringMethodRule springMethodRule = new SpringMethodRule();
    
        long input;
        long output;
    
        public FibonacciTest(long input, long output) { this.input = input; ...} 
    
        @Test
        public void testFibonacci() {
            Assert.assertEquals(output, fibonacci(input));
        }
    
        public List<Long[]> params() {
            return Arrays.asList(new Long[][] { {0, 0}, {1, 1} });
        }
    }
    
        4
  •  4
  •   Konstantin Pavlov    10 年前

    用注释测试类就足够了 @RunWith(Parameterized.class) @ContextConfiguration 使用 @Autowired 用于依赖项注入和使用 TestContextManager 在用于初始化的构造函数中,例如:

    @RunWith(Parameterized.class)
    @ContextConfiguration(classes = TestConfig.class)
    public class MyTest {
    
        @Autowired
        private DataSource dataSource;
    
        private final int param;
    
        @Parameterized.Parameters
        public static List<Object[]> params() {
            return Arrays.asList(new Object[][]{
                {1},
                {2},
            });
        }
    
        public MyTest(int p) {
            this.param = p;
            new TestContextManager(getClass()).prepareTestInstance(this);
        }
    
        @Test
        public void testSomething() {
           …
        }
    }
    
        5
  •  3
  •   Max    13 年前

    我对参数化的.class使用以下解决方案,没有任何问题: http://bmocanu.ro/coding/320/combining-junit-theoriesparameterized-tests-with-spring/

    @ContextConfiguration(value = "classpath:test-context.xml")
    public abstract class AbstractJunitTest extends AbstractJUnit4SpringContextTests {
        private static TestContextManager testContextManager = null;
        private static DAOFactory daoFactory = null;
    
        @Before
        public void initApplicationContext() throws Exception {
            if (testContextManager == null) {
                testContextManager = new TestContextManager(getClass());
                testContextManager.prepareTestInstance(this);
                daoFactory = (DAOFactory)applicationContext.getBean("daoFactory");
            }
        }
    
        protected DAOFactory getDaoFactory() throws Exception {
            return daoFactory;
        }
    }
    
    
    
    @RunWith(Parameterized.class)
    public class SomeTestClass extends AbstractJunitTest {
         ...
    }
    
        6
  •  2
  •   Arnor    7 年前

    这里是第一个没有JUnit 4.12参数化工厂的解决方案,下面是一个改进的解决方案。

    没有事务支持的静态上下文

    让Spring使用 TestContextManager 班级。

    技巧是使用一个假测试实例来获取自动连接的字段,并将它们传递给参数化测试,该测试将有效地运行。

    但请记住 prepareTestInstance() 做自动布线,但不管理测试事务和其他好东西处理 beforeTestMethod() afterTestMethod() .

    @RunWith(Parameterized.class)
    @ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
    @WebAppConfiguration
    @ActiveProfiles("test-profile")
    public class MyTest {
    
      @Parameters
      public static Collection<Object[]> params() throws Exception {
        final MyTest fakeInstance = new MyTest();
        final TestContextManager contextManager = new TestContextManager(MyTest.class);
        contextManager.prepareTestInstance(fakeInstance);
        final WebApplicationContext context = fakeInstance.context;
    
        // Do what you need with Spring context, you can even access web resources
        final Resource[] files = context.getResources("path/files");
        final List<Object[]> params = new ArrayList<>();
        for (Resource file : files) {
          params.add(new Object[] {file, context});
        }
        return params;
      }
    
      @Parameter
      public Resource file;
      @Autowired
      @Parameter(1)
      public WebApplicationContext context;
    }
    

    但是,如果有很多自动连线字段,则会出现一个缺点,因为必须手动将它们传递给数组参数。

    带全弹簧支架的参数化工厂

    Junit 4.12介绍 ParametersRunnerFactory 它允许将参数化测试和弹簧注射相结合。

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

    工厂可以添加到以前的测试类中,以提供像 test transaction , reinit dirty context servlet test . 当然,不再需要将自动连线字段从假测试实例传递到参数化测试。

    @UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
    @RunWith(Parameterized.class)
    @ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
    @WebAppConfiguration
    @Transactional
    @TransactionConfiguration
    public class MyTransactionalTest {
    
      @Parameters
      public static Collection<Object[]> params() throws Exception {
        final MyTransactionalTest fakeInstance = new MyTransactionalTest();
        final TestContextManager contextManager = new TestContextManager(MyTransactionalTest.class);
        contextManager.prepareTestInstance(fakeInstance);
        final WebApplicationContext context = fakeInstance.context;
    
        // Do what you need with Spring context, you can even access web resources
        final Resource[] files = context.getResources("path/files");
        final List<Object[]> params = new ArrayList<>();
        for (Resource file : files) {
          params.add(new Object[] {file});
        }
        return params;
      }
    
      @Parameter
      public Resource file;
    
      @Autowired
      private WebApplicationContext context;
    }
    
        7
  •  0
  •   Thierry Roy    15 年前

    记住,Spring注入使用@autowired,但也使用setter。因此,不要使用@autowired,而是使用setter:

    private static String directory;
    
    public void setDirectory(String directory) {
        this.directory = directory;
    }
    
    public static String getDirectory() {
         return directory;
    }