java - ejemplo - springjunit4classrunner example
¿Cómo puedo usar el corredor de prueba de JUnit parametrizado con un campo que se inyecta con Spring? (7)
Aquí hay una primera solución sin JUnit 4.12 parametrizada de fábrica, debajo de una solución mejorada con ella.
Contexto estático sin soporte transaccional
Deje que Spring realice todos los análisis de configuración y el cableado automático con la clase TestContextManager .
El truco consiste en utilizar una instancia de prueba falsa para obtener campos de conexión automática y pasarlos a la prueba parametrizada que se ejecutará de manera efectiva.
Pero tenga en cuenta que prepareTestInstance() hace el autowiring pero no administra la transacción de prueba y otras cosas agradables manejadas por beforeTestMethod()
y 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;
}
Sin embargo, aparece un inconveniente si tiene muchos campos con conexión automática porque tiene que pasarlos manualmente a los parámetros de la matriz.
Fábrica parametrizada con soporte completo de muelles.
JUnit 4.12 introduce ParametersRunnerFactory que permite combinar la prueba parametrizada y la inyección Spring.
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;
}
};
}
}
La fábrica se puede agregar a la clase de prueba anterior para brindar soporte completo de Spring como transacción de prueba , reinicio sucio y prueba de servlet . Y, por supuesto, ya no hay necesidad de pasar campos de autocontrol desde una instancia de prueba falsa a una prueba parametrizada.
@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;
}
Estoy usando Spring para inyectar la ruta a un directorio en mis pruebas de unidad. Dentro de este directorio hay una serie de archivos que deben usarse para generar datos de prueba para casos de prueba parametrizados utilizando el corredor de prueba Parameterized . Desafortunadamente, el corredor de prueba requiere que el método que proporciona los parámetros sea estático. Esto no funciona para mi situación porque el directorio solo se puede inyectar en un campo no estático. ¿Alguna idea de cómo puedo solucionar esto?
Es suficiente anotar la clase de prueba con @RunWith(Parameterized.class)
y @ContextConfiguration
, usar @Autowired
para inyección de dependencia y usar TestContextManager
en el constructor para la inicialización, por ejemplo:
@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() {
…
}
}
Para alguien que lea esto a finales de 2015 o más tarde, Spring 4.2 tiene, además de SpringJUnit4ClassRunner, agregó SpringClassRule y SpringMethodRule que aprovechan el soporte para Spring TestContext Framework .
Esto significa soporte de primera clase para cualquier Runner como MockitoJUnitRunner
o 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} });
}
}
Puedes usar un TestContextManager desde Spring. En este ejemplo, estoy usando teorías en lugar de parametrizado.
@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);
}
}
Encontré esta solución aquí: Cómo hacer pruebas de teorías / parametrizadas con Spring
Recuerde que Spring inyectar utilizando @Autowired, pero también con setter. Entonces, en lugar de usar @Autowired, usa el setter:
private static String directory;
public void setDirectory(String directory) {
this.directory = directory;
}
public static String getDirectory() {
return directory;
}
Supongo que está utilizando JUnit 4.X ya que mencionó el corredor de prueba parametrizado. Esto implica que no está utilizando @RunWith (SpringJUnit4ClassRunner). No es un problema, solo una lista de mis suposiciones.
Lo siguiente usa Spring para obtener el directorio de archivos de prueba del archivo XML. No se inyecta, pero los datos todavía están disponibles para su prueba. Y en un método estático no menos.
La única desventaja que veo es que puede significar que su configuración Spring se está analizando / configurando varias veces. Usted podría cargar solo un archivo más pequeño con información específica de la prueba si es necesario.
@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
}
Utilizo la siguiente solución con Parameterized.class sin ningún problema: 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 {
...
}