java - test - Excluyendo una prueba no param en la clase de prueba parametrizada
junit testwith (8)
JUnit 5
A partir de Junit 5.0.0, ahora puede anotar sus métodos de prueba con @ParameterizedTest
. Entonces no hay necesidad de clases internas. Hay muchas maneras de suministrar los argumentos a la prueba parametrizada aparte de ValueSource como se muestra a continuación. Consulte la guía de usuario oficial de junit para más detalles:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class ComponentTest {
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
public void testCaseUsingParams(String candidate) throws Exception {
}
@Test
public void testCaseWithoutParams() throws Exception {
}
}
JUnit 4
Si todavía está utilizando Junit 4 (probé con v4.8.2) puede usar el corredor incluido junto con las clases internas y el corredor parametrizado:
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Enclosed.class)
public class ComponentTest {
@RunWith(Parameterized.class)
public static class ComponentParamTests {
@Parameters
...
@Test
public void testCaseUsingParams() throws Exception {
}
}
public static class ComponentSingleTests {
@Test
public void testCaseWithoutParams() throws Exception {
}
}
}
¿Hay alguna anotación en JUnit para excluir una prueba no param en la clase de prueba parametrizada?
Hice algo similar a la Solución de Mateo. Sin embargo, creé dos nuevos archivos java que amplían el archivo actual para que los ComponentSingleTests no se ejecuten dos veces. De esta forma, pueden compartir variables de miembros comunes y métodos de ayuda de la clase principal. El problema que tuve con la Solución de Matthew fue que mi única prueba se ejecutó dos veces en vez de una. La clase Enclosed (que extiende Suite.class) hará que la prueba se ejecute dos veces como se describe en este enlace Evite que las pruebas de junio se ejecuten dos veces
ComponentTest.java
public class ComponentTest {
public int sharedMemberVariables;
...
}
ComponentParamTests.java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class ComponentParamTests extends ComponentTest {
@Parameters
...
@Test
public void testCaseUsingParams() throws Exception {
}
}
ComponentSingleTests.java
import org.junit.Test;
public class ComponentSingleTests {
@Test
public void testCaseWithoutParams() throws Exception {
...
}
}
No. La mejor práctica es mover esas pruebas no parametrizadas a una clase diferente (archivo .java)
Parece que TestNG no sufre este problema . No estoy tan desesperado, así que modifiqué la clase incorporada parametrizada para admitir esta característica. Simplemente anote las pruebas aplicables como @NonParameterized. Tenga en cuenta que esta clase solo funciona con sus anotaciones, es decir, verifica sus importaciones.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
/**
* <p>
* The custom runner <code>Parameterized</code> implements parameterized tests.
* When running a parameterized test class, instances are created for the
* cross-product of the test methods and the test data elements.
* </p>
* For example, to test a Fibonacci function, write:
*
* <pre>
* @RunWith(Parameterized.class)
* public class FibonacciTest {
* @Parameters
* public static List<Object[]> data() {
* return Arrays.asList(new Object[][] {
* Fibonacci,
* { {0, 0}, {1, 1}, {2, 1}, {3, 2}, {4, 3}, {5, 5},
* {6, 8}}});
* }
*
* private int fInput;
*
* private int fExpected;
*
* public FibonacciTest(int input, int expected) {
* fInput = input;
* fExpected = expected;
* }
*
* @Test
* public void test() {
* assertEquals(fExpected, Fibonacci.compute(fInput));
* }
* }
* </pre>
* <p>
* Each instance of <code>FibonacciTest</code> will be constructed using the
* two-argument constructor and the data values in the
* <code>@Parameters</code> method.
* </p>
*/
public class Parameterized extends Suite {
/**
* Annotation for a method which provides parameters to be injected into the
* test class constructor by <code>Parameterized</code>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
}
/**
* Annotation for a methods which should not be parameterized
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface NonParameterized {
}
private class TestClassRunnerForParameters extends
BlockJUnit4ClassRunner {
private final int fParameterSetNumber;
private final List<Object[]> fParameterList;
TestClassRunnerForParameters(Class<?> type,
List<Object[]> parameterList, int i) throws InitializationError {
super(type);
fParameterList = parameterList;
fParameterSetNumber = i;
}
@Override
public Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(
computeParams());
}
private Object[] computeParams() throws Exception {
try {
return fParameterList.get(fParameterSetNumber);
} catch (ClassCastException e) {
throw new Exception(String.format(
"%s.%s() must return a Collection of arrays.",
getTestClass().getName(), getParametersMethod(
getTestClass()).getName()));
}
}
@Override
protected String getName() {
return String.format("[%s]", fParameterSetNumber);
}
@Override
protected String testName(final FrameworkMethod method) {
return String.format("%s[%s]", method.getName(),
fParameterSetNumber);
}
@Override
protected void validateConstructor(List<Throwable> errors) {
validateOnlyOneConstructor(errors);
}
@Override
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
@Override
protected List<FrameworkMethod> computeTestMethods() {
List<FrameworkMethod> ret = super.computeTestMethods();
for (Iterator<FrameworkMethod> i = ret.iterator(); i.hasNext();) {
FrameworkMethod frameworkMethod =
(FrameworkMethod) i.next();
if (isParameterized() ^
!frameworkMethod.getMethod().isAnnotationPresent(
NonParameterized.class)) {
i.remove();
}
}
return ret;
}
protected boolean isParameterized() {
return true;
}
}
private class TestClassRunnerForNonParameterized extends
TestClassRunnerForParameters {
TestClassRunnerForNonParameterized(Class<?> type,
List<Object[]> parameterList, int i)
throws InitializationError {
super(type, parameterList, i);
}
protected boolean isParameterized() {
return false;
}
}
private final ArrayList<Runner> runners = new ArrayList<Runner>();
/**
* Only called reflectively. Do not use programmatically.
*/
public Parameterized(Class<?> klass) throws Throwable {
super(klass, Collections.<Runner> emptyList());
List<Object[]> parametersList = getParametersList(getTestClass());
if (parametersList.size() > 0) {
try {
runners.add(new TestClassRunnerForNonParameterized(
getTestClass()
.getJavaClass(), parametersList, 0));
} catch (Exception e) {
System.out.println("No non-parameterized tests.");
}
}
try {
for (int i = 0; i < parametersList.size(); i++) {
runners.add(new TestClassRunnerForParameters(getTestClass()
.getJavaClass(),
parametersList, i));
}
} catch (Exception e) {
System.out.println("No parameterized tests.");
}
}
@Override
protected List<Runner> getChildren() {
return runners;
}
@SuppressWarnings("unchecked")
private List<Object[]> getParametersList(TestClass klass)
throws Throwable {
return (List<Object[]>) getParametersMethod(klass).invokeExplosively(
null);
}
private FrameworkMethod getParametersMethod(TestClass testClass)
throws Exception {
List<FrameworkMethod> methods = testClass
.getAnnotatedMethods(Parameters.class);
for (FrameworkMethod each : methods) {
int modifiers = each.getMethod().getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
return each;
}
throw new Exception("No public static parameters method on class "
+ testClass.getName());
}
}
Actualización: estoy tratando de agregar este tipo de cosas a junit.
Pude hacer algo muy similar a la respuesta de Matthew Madson y me pareció útil crear una clase base para encapsular la configuración y las funciones de ayuda comunes entre las pruebas individuales y param. Esto funciona sin usar Enclosed.class .
@RunWith(Suite.class)
@SuiteClasses({ComponentTest.ComponentParamTests.class, ComponentTest.ComponentSingleTests.class})
public class ComponentTest {
public static class TestBase {
@Spy
...
@Before
...
}
@RunWith(Parameterized.class)
public static class ComponentParamTests extends TestBase{
@Parameter
...
@Parameters
...
@Test
...
}
public static class ComponentSingleTests extends TestBase{
@Test
...
}
}
Suponiendo que usa Parametrized.class para ejecutar su clase de prueba, marque todas las pruebas no parametrizadas como @Ignored. De lo contrario, puede crear una clase interna estática para agrupar todas las pruebas parametrizadas y otra para no parametrizar.
Acabo de descubrir que uno puede usar JUnitParams . Convertí una de mis pruebas ahora para usarla y funciona muy bien.
El corredor de prueba Zohhak es una forma más sencilla de parametrizar pruebas específicas. Gracias Piotr!