パラメータ化されたテストクラスの非paramテストを除外するためのJUnitの注釈はありますか?
Junit 5.0.0以降では、テストメソッドに@ParameterizedTest
で注釈を付けることができます。したがって、内部クラスは必要ありません。以下に示すように、ValueSource以外にもパラメーター化されたテストに引数を提供する方法はたくさんあります。詳細は junit公式ユーザーガイド を参照してください。
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(v4.8.2でテストしました)を使用している場合は、内部クラスおよびパラメーター化されたランナーと組み合わせてEnclosedランナーを使用できます。
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 {
}
}
}
私は 見つけたばかりJUnitParams を使用できます。私は今、私のテストの1つを使用するように変換しましたが、それは美しく機能します。
いいえ。ベストプラクティスは、パラメーター化されていないテストを別のクラス(.Javaファイル)に移動することです。
Zohhak test runner は、特定のテストをパラメーター化するためのより簡単な方法です。ピョートルありがとう!
Matthew Madsonの回答と非常によく似たことができ、セットアップと単一のテストとparamテストの間の共通のヘルパー関数をカプセル化する基本クラスを作成すると便利であることがわかりました。これは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
...
}
}
春のブートMockMvcでテストを書いているときにこの問題に陥りました2つのクラスを別々に作成しましたJavaファイル(1つはParameterizedTestおよびその他のSingleTest)およびそれらのスイートを作成します。これは、内部クラスが静的メンバーに対してエラーを作成し、静的メンバーに対してエラーを作成しなかったためです。クラス。
annotationsの代わりにJava functionからパラメーターを取得したい場合:
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input, boolean expected) {
assertEquals(expected, Strings.isBlank(input));
}
private static Stream<Arguments> provideStringsForIsBlank() {
return Stream.of(
Arguments.of(null, true),
Arguments.of("", true),
Arguments.of(" ", true),
Arguments.of("not blank", false)
);
}
TestNGはこの問題の影響を受けません のようです。私はそれほど絶望的ではないので、この機能をサポートするように組み込みのParameterizedクラスを変更しました。該当するテストに@NonParameterizedと注釈を付けるだけです。このクラスはonアノテーションでのみ機能することに注意してください。つまり、インポートを確認します。
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());
}
}
私はマシューの解決策に似た何かをしました。ただし、ComponentSingleTestsが2回実行されないように、現在のファイルを拡張する2つの新しいJava=ファイルを作成しました。これにより、共通のメンバー変数と親クラスのヘルパーメソッドを共有できます。問題私のマシューのソリューションでは、Enclosed.class(Suite.classを拡張)がこのリンクで説明されているようにテストを2回実行するため、1つのテストが1回ではなく2回実行されていました junitテストが2回実行されないようにする)
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 {
...
}
}
Parametrized.classを使用してテストクラスを実行するとします。パラメータ化されていないすべてのテストを@Ignoredとしてマークします。それ以外の場合は、静的な内部クラスを作成して、すべてのパラメーター化されたテストと別のテストをグループ化できます-パラメーター化されていない場合。