답변:
이 기능은 JUnit 4.11 로 만들어졌습니다 .
매개 변수가 지정된 테스트의 이름을 변경하려면 다음과 같이 말합니다.
@Parameters(name="namestring")
namestring
문자열은 다음과 같은 특수 자리 표시자를 가질 수 있습니다.
{index}
-이 인수 세트의 인덱스 기본값 namestring
은 {index}
입니다.{0}
-이 테스트 호출의 첫 번째 매개 변수 값{1}
-두 번째 매개 변수 값테스트의 최종 이름은 namestring
아래에 표시된대로 테스트 방법의 이름이며 뒤에 괄호 가 붙습니다 .
예를 들어 ( Parameterized
주석에 대한 단위 테스트에서 수정 ) :
@RunWith(Parameterized.class)
static public class FibonacciTest {
@Parameters( name = "{index}: fib({0})={1}" )
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
private final int fInput;
private final int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
fExpected= expected;
}
@Test
public void testFib() {
assertEquals(fExpected, fib(fInput));
}
private int fib(int x) {
// TODO: actually calculate Fibonacci numbers
return 0;
}
}
이름이 같은 줄 것이다 testFib[1: fib(1)=1]
및 testFib[4: fib(4)=3]
. testFib
이름 의 일부는의 메소드 이름입니다 @Test
.
{0}
와 {1}
배열은? JUnit은 이상적으로 호출 Arrays.toString({0})
하지 않아야한다 {0}.toString()
. 예를 들어 내 data()
메서드는을 반환합니다 Arrays.asList(new Object[][] {{ new int[] { 1, 3, 2 }, new int[] { 1, 2, 3 } }});
.
JUnit 4.5를 살펴보면 해당 러너는 로직이 Parameterized 클래스의 개인 클래스에 묻혀 있기 때문에이를 지원하지 않습니다. JUnit Parameterized 러너를 사용할 수 없으며 대신 이름의 개념을 이해하는 이름을 직접 만들 수 있습니다 (이름을 설정하는 방법에 대한 질문으로 이어짐).
JUnit 관점에서 증분을 전달하는 대신 쉼표로 구분 된 인수를 전달하는 것이 좋습니다. TestNG가이를 수행합니다. 이 기능이 중요한 경우 www.junit.org에서 참조하는 yahoo 메일 링리스트에 의견을 남길 수 있습니다.
JUnit 4.3.1을 사용할 때 최근에 동일한 문제가 발생했습니다. LabelledParameterized라는 Parameterized를 확장하는 새로운 클래스를 구현했습니다. JUnit 4.3.1, 4.4 및 4.5를 사용하여 테스트되었습니다. @Parameters 메서드에서 각 매개 변수 배열의 첫 번째 인수에 대한 String 표현을 사용하여 Description 인스턴스를 재구성합니다. 이 코드는 다음에서 확인할 수 있습니다.
http://code.google.com/p/migen/source/browse/trunk/java/src/.../LabelledParameterized.java?r=3789
그리고 그 사용 예 :
http://code.google.com/p/migen/source/browse/trunk/java/src/.../ServerBuilderTest.java?r=3789
테스트 설명은 Eclipse에서 멋지게 형식화되어 실패한 테스트를 훨씬 쉽게 찾을 수 있기 때문에 원했습니다. 다음 며칠 / 주 동안 수업을 더 세분화하고 문서화 할 것입니다. '?'를 삭제하십시오. 출혈 가장자리를 원할 경우 URL의 일부입니다. :-)
사용하려면 해당 클래스 (GPL v3)를 복사하고 매개 변수 목록의 첫 번째 요소가 합리적인 레이블이라고 가정하고 @RunWith (Parameterized.class)를 @RunWith (LabelledParameterized.class)로 변경하면됩니다.
JUnit의 이후 릴리스 에서이 문제를 해결하는지 알 수는 없지만, 공동 개발자가 모두 업데이트해야하고 재 툴링보다 우선 순위가 높기 때문에 JUnit을 업데이트 할 수 없습니다. 따라서 클래스의 작업은 여러 버전의 JUnit에서 컴파일 할 수 있습니다.
참고 : 위에 나열된 것과 같이 다른 JUnit 버전에서 실행되도록 일부 리플렉션 jiggery-pokery가 있습니다. 구체적의 JUnit 4.3.1 버전이 발견 될 수있다 여기서 , JUnit을 4.4 및 4.5 그리고 여기 .
execute[0], execute[1] ... execute[n]
생성 된 테스트 보고서에 이름이 지정 됩니다.
와 Parameterized
모델로, 나는 내 자신의 사용자 정의 테스트 러너 / 제품군을 썼다 - 절반 밖에 시간 정도 걸렸다. darrenp와는 약간 다르 LabelledParameterized
므로 첫 번째 매개 변수에 의존하지 않고 명시 적으로 이름을 지정할 수 있습니다 toString()
.
배열을 싫어하기 때문에 배열을 사용하지 않습니다. :)
public class PolySuite extends Suite {
// //////////////////////////////
// Public helper interfaces
/**
* Annotation for a method which returns a {@link Configuration}
* to be injected into the test class constructor
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Config {
}
public static interface Configuration {
int size();
Object getTestValue(int index);
String getTestName(int index);
}
// //////////////////////////////
// Fields
private final List<Runner> runners;
// //////////////////////////////
// Constructor
/**
* Only called reflectively. Do not use programmatically.
* @param c the test class
* @throws Throwable if something bad happens
*/
public PolySuite(Class<?> c) throws Throwable {
super(c, Collections.<Runner>emptyList());
TestClass testClass = getTestClass();
Class<?> jTestClass = testClass.getJavaClass();
Configuration configuration = getConfiguration(testClass);
List<Runner> runners = new ArrayList<Runner>();
for (int i = 0, size = configuration.size(); i < size; i++) {
SingleRunner runner = new SingleRunner(jTestClass, configuration.getTestValue(i), configuration.getTestName(i));
runners.add(runner);
}
this.runners = runners;
}
// //////////////////////////////
// Overrides
@Override
protected List<Runner> getChildren() {
return runners;
}
// //////////////////////////////
// Private
private Configuration getConfiguration(TestClass testClass) throws Throwable {
return (Configuration) getConfigMethod(testClass).invokeExplosively(null);
}
private FrameworkMethod getConfigMethod(TestClass testClass) {
List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Config.class);
if (methods.isEmpty()) {
throw new IllegalStateException("@" + Config.class.getSimpleName() + " method not found");
}
if (methods.size() > 1) {
throw new IllegalStateException("Too many @" + Config.class.getSimpleName() + " methods");
}
FrameworkMethod method = methods.get(0);
int modifiers = method.getMethod().getModifiers();
if (!(Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new IllegalStateException("@" + Config.class.getSimpleName() + " method \"" + method.getName() + "\" must be public static");
}
return method;
}
// //////////////////////////////
// Helper classes
private static class SingleRunner extends BlockJUnit4ClassRunner {
private final Object testVal;
private final String testName;
SingleRunner(Class<?> testClass, Object testVal, String testName) throws InitializationError {
super(testClass);
this.testVal = testVal;
this.testName = testName;
}
@Override
protected Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(testVal);
}
@Override
protected String getName() {
return testName;
}
@Override
protected String testName(FrameworkMethod method) {
return testName + ": " + method.getName();
}
@Override
protected void validateConstructor(List<Throwable> errors) {
validateOnlyOneConstructor(errors);
}
@Override
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
}
}
그리고 예 :
@RunWith(PolySuite.class)
public class PolySuiteExample {
// //////////////////////////////
// Fixture
@Config
public static Configuration getConfig() {
return new Configuration() {
@Override
public int size() {
return 10;
}
@Override
public Integer getTestValue(int index) {
return index * 2;
}
@Override
public String getTestName(int index) {
return "test" + index;
}
};
}
// //////////////////////////////
// Fields
private final int testVal;
// //////////////////////////////
// Constructor
public PolySuiteExample(int testVal) {
this.testVal = testVal;
}
// //////////////////////////////
// Test
@Ignore
@Test
public void odd() {
assertFalse(testVal % 2 == 0);
}
@Test
public void even() {
assertTrue(testVal % 2 == 0);
}
}
junit4.8.2부터는 단순히 Parameterized 클래스를 복사하여 MyParameterized 클래스를 작성할 수 있습니다. TestClassRunnerForParameters에서 getName () 및 testName () 메소드를 변경하십시오.
JUnitParams를 시도 할 수도 있습니다 : http://code.google.com/p/junitparams/
당신은 같은 방법을 만들 수 있습니다
@Test
public void name() {
Assert.assertEquals("", inboundFileName);
}
항상 사용하지는 않지만 정확히 143의 테스트 번호를 알아내는 것이 유용합니다.
Assert 및 친구들에게 정적 가져 오기를 광범위하게 사용하므로 어설 션을 재정의하기가 쉽습니다.
private <T> void assertThat(final T actual, final Matcher<T> expected) {
Assert.assertThat(editThisToDisplaySomethingForYourDatum, actual, expected);
}
예를 들어, 테스트 클래스에 "name"필드를 추가하고 생성자에서 초기화하여 테스트 실패시이를 표시 할 수 있습니다. 각 테스트마다 매개 변수 배열의 첫 번째 요소로 전달하십시오. 또한 데이터 레이블을 지정하는 데 도움이됩니다.
public ExampleTest(final String testLabel, final int one, final int two) {
this.testLabel = testLabel;
// ...
}
@Parameters
public static Collection<Object[]> data() {
return asList(new Object[][]{
{"first test", 3, 4},
{"second test", 5, 6}
});
}
그 중 어느 것도 나를 위해 일하지 않았으므로 Parameterized의 소스를 얻었고 수정하여 새로운 테스트 러너를 만들었습니다. 많이 바꿀 필요는 없었지만 IT는 효과가 있습니다 !!!
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Assert;
import org.junit.internal.runners.ClassRoadie;
import org.junit.internal.runners.CompositeRunner;
import org.junit.internal.runners.InitializationError;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.internal.runners.MethodValidator;
import org.junit.internal.runners.TestClass;
import org.junit.runner.notification.RunNotifier;
public class LabelledParameterized extends CompositeRunner {
static class TestClassRunnerForParameters extends JUnit4ClassRunner {
private final Object[] fParameters;
private final String fParameterFirstValue;
private final Constructor<?> fConstructor;
TestClassRunnerForParameters(TestClass testClass, Object[] parameters, int i) throws InitializationError {
super(testClass.getJavaClass()); // todo
fParameters = parameters;
if (parameters != null) {
fParameterFirstValue = Arrays.asList(parameters).toString();
} else {
fParameterFirstValue = String.valueOf(i);
}
fConstructor = getOnlyConstructor();
}
@Override
protected Object createTest() throws Exception {
return fConstructor.newInstance(fParameters);
}
@Override
protected String getName() {
return String.format("%s", fParameterFirstValue);
}
@Override
protected String testName(final Method method) {
return String.format("%s%s", method.getName(), fParameterFirstValue);
}
private Constructor<?> getOnlyConstructor() {
Constructor<?>[] constructors = getTestClass().getJavaClass().getConstructors();
Assert.assertEquals(1, constructors.length);
return constructors[0];
}
@Override
protected void validate() throws InitializationError {
// do nothing: validated before.
}
@Override
public void run(RunNotifier notifier) {
runMethods(notifier);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
}
private final TestClass fTestClass;
public LabelledParameterized(Class<?> klass) throws Exception {
super(klass.getName());
fTestClass = new TestClass(klass);
MethodValidator methodValidator = new MethodValidator(fTestClass);
methodValidator.validateStaticMethods();
methodValidator.validateInstanceMethods();
methodValidator.assertValid();
int i = 0;
for (final Object each : getParametersList()) {
if (each instanceof Object[])
add(new TestClassRunnerForParameters(fTestClass, (Object[]) each, i++));
else
throw new Exception(String.format("%s.%s() must return a Collection of arrays.", fTestClass.getName(), getParametersMethod().getName()));
}
}
@Override
public void run(final RunNotifier notifier) {
new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
public void run() {
runChildren(notifier);
}
}).runProtected();
}
private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception {
return (Collection<?>) getParametersMethod().invoke(null);
}
private Method getParametersMethod() throws Exception {
List<Method> methods = fTestClass.getAnnotatedMethods(Parameters.class);
for (Method each : methods) {
int modifiers = each.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
return each;
}
throw new Exception("No public static parameters method on class " + getName());
}
public static Collection<Object[]> eachOne(Object... params) {
List<Object[]> results = new ArrayList<Object[]>();
for (Object param : params)
results.add(new Object[] { param });
return results;
}
}
해결 방법은 모든 Throwable을 캐치하여 매개 변수에 대한 모든 정보를 포함하는 사용자 정의 메시지가있는 새 Throwable에 중첩시키는 것입니다. 메시지는 스택 추적에 나타납니다. 이것은 모든 어설 션, 오류 및 예외가 Throwable의 하위 클래스이므로 테스트가 실패 할 때마다 작동합니다.
내 코드는 다음과 같습니다
@RunWith(Parameterized.class)
public class ParameterizedTest {
int parameter;
public ParameterizedTest(int parameter) {
super();
this.parameter = parameter;
}
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { {1}, {2} });
}
@Test
public void test() throws Throwable {
try {
assertTrue(parameter%2==0);
}
catch(Throwable thrown) {
throw new Throwable("parameter="+parameter, thrown);
}
}
}
실패한 테스트의 스택 추적은 다음과 같습니다.
java.lang.Throwable: parameter=1
at sample.ParameterizedTest.test(ParameterizedTest.java:34)
Caused by: java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.assertTrue(Assert.java:43)
at org.junit.Assert.assertTrue(Assert.java:54)
at sample.ParameterizedTest.test(ParameterizedTest.java:31)
... 31 more
액세스 된 매개 변수 (예 : "{0}"
항상 표시를 리턴 함) toString()
는 한 가지 해결 방법은 익명 구현을 수행하고 toString()
각 경우에 대체하는 것 입니다.
public static Iterable<? extends Object> data() {
return Arrays.asList(
new MyObject(myParams...) {public String toString(){return "my custom test name";}},
new MyObject(myParams...) {public String toString(){return "my other custom test name";}},
//etc...
);
}