मानकीकृत परीक्षणों के नाम बदलना


204

क्या JUnit4 में पैरामीटराइज्ड परीक्षणों का उपयोग करते समय मेरे खुद के कस्टम टेस्ट केस नाम सेट करने का कोई तरीका है?

मैं डिफ़ॉल्ट - [Test class].runTest[n]- को कुछ सार्थक बदलना चाहूंगा ।

जवाबों:


299

इस फीचर ने इसे 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)।


4
कोई कारण नहीं है कि यह 4.11 में नहीं होगा, यह मास्टर में है। अब जब 4.11 उपलब्ध होगा, तो यह एक अच्छा प्रश्न है :-)
मैथ्यू फ़रवेल

1
4.11 अब बीटा में है, और ऊपर दिए गए लिंक से डाउनलोड किया जा सकता है :-)
rescdsk

2
हां, लेकिन एक बग है। यदि आप पैरामीटर "नाम" मान में कोष्ठक डालते हैं जैसे आप इस पोस्टिंग में कर रहे हैं, तो यह ग्रहण में इकाई परीक्षण नाम के प्रदर्शन को तोड़ता है।
djangofan

7
महान, लेकिन क्या होगा {0}और {1}सरणियाँ हैं? JUnit को आदर्श रूप से कॉल करना चाहिए Arrays.toString({0}), नहीं {0}.toString()। उदाहरण के लिए, मेरी data()विधि वापस आती है Arrays.asList(new Object[][] {{ new int[] { 1, 3, 2 }, new int[] { 1, 2, 3 } }});
dogbane

1
@djangofan यह एक 8 साल पुराना ग्रहण बग है: bugs.eclipse.org/bugs/show_bug.cgi?id=102512
पूल

37

JUnit 4.5 को देखते हुए, इसका धावक स्पष्ट रूप से समर्थन नहीं करता है, क्योंकि यह तर्क एक निजी वर्ग के अंदर Parameterized वर्ग के अंदर दफन है। आप JUnit Parameterized धावक का उपयोग नहीं कर सकते हैं, और अपना खुद का निर्माण कर सकते हैं जो नामों की अवधारणा को समझेगा (जो इस सवाल का कारण बनता है कि आप नाम कैसे सेट कर सकते हैं ...)।

JUnit के नजरिए से, यह अच्छा होगा अगर (या इसके अलावा) सिर्फ एक वेतन वृद्धि पारित किया जाए, तो वे अल्पविराम वाले तर्कों को पारित करेंगे। TestNG ऐसा करता है। यदि यह सुविधा आपके लिए महत्वपूर्ण है, तो आप www.junit.org पर संदर्भित याहू मेलिंग सूची पर टिप्पणी कर सकते हैं।


3
मैं बहुत सराहना करता हूँ अगर वहाँ JUnit में इसके लिए एक सुधार है!
गुरदा

17
बस की जाँच की, इस पर एक उत्कृष्ट सुविधा अनुरोध है: github.com/KentBeck/junit/issues#issue/44 कृपया इसे वोट करें।
reccles

8
@Frank, मुझे लगता है कि इस मुद्दे को संबोधित करने वाली रिलीज़ अभी जारी नहीं हुई है। यह JUnit 4.11 में होगा। उस समय (यह मानते हुए कि डिजाइन एक ही है) यह निर्दिष्ट करने के पाठ के तरीके के बारे में होगा कि आप परीक्षण को नाम कैसे देते हैं, जिसमें नाम के रूप में पैरामीटर भी शामिल हैं। बहुत अच्छा, वास्तव में।
यिशई

5
JUnit 4.11 अब जारी किया गया है :-)
rescdsk

7
यहाँ भविष्य के संदर्भ के लिए मूल मुद्दे github.com/junit-team/junit/issues/44 की अद्यतन लिंक है
kldavis4

20

मैं हाल ही में JUnit 4.3.1 का उपयोग करते समय एक ही समस्या को लेकर आया था। मैंने एक नया वर्ग कार्यान्वित किया, जो कि लैम्बर्डपैरिमाइज्ड कहे जाने वाले Parameterized का विस्तार करता है। यह JUnit 4.3.1, 4.4 और 4.5 का उपयोग करके परीक्षण किया गया है। यह @ पैरामीटर सिस्टम से प्रत्येक पैरामीटर सरणी के पहले तर्क के स्ट्रिंग प्रतिनिधित्व का उपयोग करके विवरण उदाहरण को फिर से संगठित करता है। आप इसके लिए कोड देख सकते हैं:

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

एक्लिप्स में परीक्षण विवरण अच्छी तरह से प्रारूपित होता है जो कि मैं चाहता था क्योंकि यह विफल परीक्षणों को खोजने में बहुत आसान बनाता है! मैं शायद अगले कुछ दिनों / हफ्तों में कक्षाओं को और अधिक परिष्कृत और प्रलेखित करूंगा। गिराओ '?' यदि आप ब्लीडिंग एज चाहते हैं तो URL का हिस्सा। :-)

इसका उपयोग करने के लिए, आपको केवल उस श्रेणी (GPL v3) की प्रतिलिपि बनाना है, और @RunWith (LabelledParameterized.class) को अपने पैरामीटर सूची के पहले तत्व को मानते हुए @RunWith (Parameterized.class) को बदल दें।

मुझे नहीं पता कि बाद में किसी भी तरह से JUnit की रिलीज़ इस मुद्दे को संबोधित करती है लेकिन फिर भी अगर उन्होंने किया, तो मैं JUnit को अपडेट नहीं कर सकता क्योंकि मेरे सभी सह-डेवलपर्स को भी अपडेट करना होगा और हमारे पास री-टूलिंग की तुलना में उच्च प्राथमिकताएँ हैं। इसलिए कक्षा में काम को JUnit के कई संस्करणों द्वारा संकलित किया जाना है।


नोट: कुछ प्रतिबिंब गुड़-पोकरी है ताकि यह ऊपर सूचीबद्ध के रूप में अलग-अलग JUnit संस्करणों में चलता रहे। विशेष रूप से JUnit 4.3.1 के लिए संस्करण यहां और JUnit 4.4 और 4.5 के लिए पाया जा सकता है


:-) मेरे एक सह-डेवलपर को आज इसके साथ एक समस्या थी क्योंकि संस्करण के रूप में उपरोक्त संदेश में मैं इंगित करता हूं JUnit 4.3.1 का उपयोग करता है (4.4 नहीं जैसा कि मैंने मूल रूप से कहा था)। वह JUnit 4.5.0 का उपयोग कर रहा है और इससे समस्याएं पैदा हुई हैं। मैं आज इन्हें संबोधित करूंगा।
darrenp

मुझे यह समझने में कुछ समय लगा कि आपको कंस्ट्रक्टर में टेस्ट नाम पास करने की आवश्यकता है , लेकिन इसे याद नहीं। कोड के लिए धन्यवाद!
जिराफ

जब तक मैं ग्रहण से परीक्षण चलाता हूं तब तक बढ़िया काम करता है। किसी को भी यह JUnit चींटी कार्य के साथ काम करने के साथ अनुभव है, हालांकि? परीक्षण रिपोर्ट का नाम execute[0], execute[1] ... execute[n]उत्पन्न परीक्षण रिपोर्ट में दिया गया है।
हेनरिक एवोन सोरेनसेन

बहुत अच्छा। एक जादू की तरह काम करता है। अच्छा होगा, यदि आप जानकारी जोड़ सकते हैं, कि "@ String लेबल, ..." को पहले पैरामीटर के रूप में जोड़ना जरूरी है।
जिया

13

साथ 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);
  }

}

6

junit4.8.2 से, आप बस Parameterized वर्ग को कॉपी करके अपना खुद का MyParameterized वर्ग बना सकते हैं। TestClassRunnerForParameters में getName () और testName () विधियों को बदलें।


मैंने यह कोशिश की, लेकिन मदद नहीं करता है। नया वर्ग बनाते समय getParametersMethod विफल रहता है।
java_enthu


2

आप एक विधि की तरह बना सकते हैं

@Test
public void name() {
    Assert.assertEquals("", inboundFileName);
}

हालांकि मैं हर समय इसका इस्तेमाल नहीं करूंगा, यह जानने के लिए उपयोगी होगा कि टेस्ट नंबर 143 कौन सा है।


2

मैं मुखर और दोस्तों के लिए स्थैतिक आयात का व्यापक उपयोग करता हूं, इसलिए मेरे लिए मुखरता को फिर से परिभाषित करना आसान है:

private <T> void assertThat(final T actual, final Matcher<T> expected) {
    Assert.assertThat(editThisToDisplaySomethingForYourDatum, actual, expected);
}

उदाहरण के लिए, आप अपने परीक्षण वर्ग में एक "नाम" फ़ील्ड जोड़ सकते हैं, निर्माणकर्ता में इनिशियलाइज़ किया जा सकता है, और परीक्षण विफलता पर प्रदर्शित कर सकते हैं। बस इसे प्रत्येक परीक्षण के लिए अपने मापदंडों के पहले तत्वों के रूप में पास करें। यह डेटा को लेबल करने में भी मदद करता है:

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

यह ठीक है यदि परीक्षण जोर देने में विफल रहता है, लेकिन अन्य मामले भी हैं, जैसे कि यदि कोई अपवाद फेंका जाता है जो परीक्षण में विफल रहता है, या यदि परीक्षण को फेंक दिए जाने के अपवाद की उम्मीद है, तो उस नाम के बारे में सोचें जो उपरि होना चाहिए ढांचे द्वारा नियंत्रित किया जाता है।
यिशै

2

इसमें से कोई भी मेरे लिए काम नहीं कर रहा था, इसलिए मुझे Parameterized के लिए स्रोत मिला और इसे संशोधित करके एक नया टेस्ट रनर बनाया गया। मुझे बहुत कुछ बदलना नहीं था लेकिन यह काम करता है !!!

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

2

एक वर्कअराउंड सभी थ्रोवेबल्स को एक नए संदेश में एक कस्टम संदेश के साथ पकड़ने और घोंसला बनाने के लिए होगा जिसमें मापदंडों के बारे में सभी जानकारी होती है। संदेश स्टैक ट्रेस में दिखाई देगा। यह तब भी काम करता है जब सभी परीक्षण, त्रुटियों और अपवादों के लिए एक परीक्षण विफल हो जाता है क्योंकि वे सभी थ्रोबेबल के उपवर्ग हैं।

मेरा कोड इस तरह दिखता है:

@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

JUnitParams को dsaff के रूप में देखें, HTML रिपोर्ट में पैरामीटर परीक्षण पद्धति विवरण बनाने के लिए चींटी का उपयोग करके काम करता है।

यह LabelledParameterized और यह पता लगाने की कोशिश करने के बाद था कि यह ग्रहण के साथ काम करता है, लेकिन यह जहां तक ​​html रिपोर्ट का संबंध है, चींटी के साथ काम नहीं करता है।

चीयर्स,


0

चूंकि पैरामीटर एक्सेस किया गया है (उदाहरण के साथ "{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...
    );
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.