سؤال

هل هناك طريقة لوضع بلدي مخصص حالة اختبار الأسماء عند استخدام معلمات الاختبارات في JUnit4?

أود أن تغيير الافتراضي — [Test class].runTest[n] — إلى شيء مفيد.

هل كانت مفيدة؟

المحلول

هذه الميزة جعلت من في 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).

نصائح أخرى

وعند النظر إلى أداة JUnit 4.5، عداء لها بشكل واضح لا يدعم ذلك، كما دفن هذا المنطق داخل فئة خاصة داخل الطبقة معلمات. لا يمكن استخدام عداء معلمات أداة JUnit، وخلق الخاصة بك بدلا من شأنها أن نفهم مفهوم الأسماء (الذي يؤدي لمسألة كيف يمكن تعيين اسم ...).

ومن منظور أداة JUnit، فإنه سيكون لطيفا لو بدلا من (أو بالإضافة إلى) مجرد تمرير الزيادة، فإنها تمر الحجج بفواصل. TestNG يفعل ذلك. إذا كانت الميزة هو مهم بالنسبة لك، يمكنك التعليق على قائمة ياهو البريدية المشار إليها في www.junit.org.

كنت مؤخرا قد جاء عبر نفس المشكلة عند استخدام JUnit 4.3.1.لقد نفذت الطبقة الجديدة التي تمتد معلمات يسمى LabelledParameterized.وقد تم اختباره باستخدام 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(Parameterized.class) إلى @RunWith(LabelledParameterized.class) على افتراض العنصر الأول من القائمة المعلمة هو معقول التسمية.

أنا لا أعرف إذا كان أي الإصدارات الأحدث من JUnit معالجة هذه المسألة ولكن حتى لو لم لا أستطيع تحديث JUnit لأن جميع زملائي المطورين أن التحديث أيضا لدينا أولويات أعلى من إعادة الأدوات.ومن ثم العمل في الصف أن يكون compilable من خلال إصدارات متعددة من JUnit.


ملاحظة: هناك بعض التفكير jiggery-pokery بحيث يتم تشغيله عبر مختلف JUnit الإصدارات المذكورة أعلاه.الإصدار خصيصا JUnit 4.3.1 يمكن العثور عليها هنا و JUnit 4.4 و 4.5, هنا.

ومع Parameterized كنموذج، كتبت بلدي اختبار مخصصة عداء / جناح - لم تكن الا حوالي نصف ساعة. الأمر مختلف قليلا من LabelledParameterized darrenp في أنه يتيح لك تحديد اسم صراحة بدلا من الاعتماد على 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، يمكنك إنشاء فئة MyParameterized الخاصة بك ببساطة عن طريق نسخ الطبقة معلمات. تغيير getName () وtestName () الأساليب في TestClassRunnerForParameters.

وأنت قد تحتاج أيضا إلى محاولة JUnitParams: http://code.google.com/p/junitparams /

ويمكنك إنشاء أسلوب مثل

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

وبينما أنا لن تستخدم في كل وقت أنه سيكون من المفيد لمعرفة بالضبط الذي اختبار عدد 143 هو.

وأنا جعل الاستخدام المكثف للاستيراد ثابت لتأكيد والأصدقاء، لذلك فمن السهل بالنسبة لي أن إعادة التأكيد:

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

لا شيء من ذلك كان يعمل بالنسبة لي، لذلك أنا حصلت على مصدر للمعلمات وعدله إنشاء عداء اختبار جديد. لم يكن لديك لتغيير بكثير ولكن يعمل 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;
}
}

الحل سيكون للقبض عش كل Throwables إلى 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

تحقق من JUnitParams كما ذكر dsaff، يعمل باستخدام النمل لبناء الوصف طريقة الاختبار معلمات في تقرير أتش تي أم أل.

وكان هذا بعد محاولة LabelledParameterized وإيجاد أنه على الرغم من أنه يعمل مع كسوف أنها لا تعمل مع نملة بقدر ما يتعلق الأمر تقرير أتش تي أم أل.

وابتهاج،

ومنذ المعلمة الوصول إليها (على سبيل المثال مع "{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...
    );
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top