Как я могу создать тестовый набор в JUnit 4?

Я хотел бы создать набор тестов junit с помощью JUnit 4, где имена тестируемых классов, которые будут включены, неизвестны до тех пор, пока не будет запущен набор тестов.

В JUnit 3 я мог бы сделать это:

public final class MasterTester extends TestCase
{
  /**
   * Used by junit to specify what TestCases to run.
   * 
   * @return a suite containing what TestCases to run
   */
  public static TestSuite suite() {
    TestSuite suite = new TestSuite();

    for(Class<?> klass : gatherTestClasses()) {
      suite.addTestSuite(klass);
    }

    return suite;
  }
}

а метод gatherTestClasses() - выяснить, какие тестовые классы запускать.

В JUnit 4 в документации говорится, чтобы использовать аннотацию: @SuiteClasses({TestClass1.class, TestClass2.class...}) для создания моего тестового набора. Есть многочисленные ответы SO, показывающие, как это сделать. К сожалению, примеры, которые я вижу, похоже, не позволяют передавать динамически сгенерированный список TestClasses.

Этот SO ответ предложил бы мне подкласс BlockJUnit4ClassRunner, который я не хочу делать.

Динамически определенные тестовые сеты кажутся чем-то, что должно быть в JUnit 4 где-то. Кто-нибудь знает, где?

Ответ 1

Я обнаружил, что класс classpath весьма полезен при использовании с соглашением об именах в моих тестовых классах.

https://github.com/takari/takari-cpsuite

Вот пример:

import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;

@RunWith(ClasspathSuite.class)
@ClassnameFilters({".*UnitTest"})
public class MySuite {
}

Ответ 2

Я пробовал это с помощью JUnit 4.8, и он работает:

@RunWith(AllTests.class)
public class SomeTests
{
    public static TestSuite suite()
    {
        TestSuite suite = new TestSuite();

        suite.addTest(new JUnit4TestAdapter(Test1.class));
        suite.addTest(new JUnit4TestAdapter(Test2.class));

        return suite;
     }
}

Ответ 3

Чтобы создать динамический набор тестов, вам нужно использовать аннотацию @RunWith. Существует два способа его использования:

@RunWith(Suite.class)

Это позволяет указать, какие классы составляют соответствующий тестовый пакет. Это эквивалентно стилю JUnit 3:

import junit.framework.TestSuite;
import junit.framework.TestCase;

public final class MasterTester extends TestCase {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    suite.addTestSuite(TestClass1.class);        
    suite.addTestSuite(TestClass2.class);
    // etc...
    return suite;
  }
}

Эквивалентный класс JUnit 4 будет:

import org.junit.runners.Suite;

@RunWith(Suite.class)
@SuiteClasses({TestClass1.class, TestClass2.class})
public final class MasterTester {

}

@RunWith(AllTests.class)

Это позволяет динамически определять тесты, которые составляют набор тестов. Если ваши тесты неизвестны до выполнения, вы не можете указывать их в аннотациях. Вы можете использовать эту конструкцию. Итак, если код JUnit 3:

import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.framework.Test;

public final class MasterTester extends TestCase {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    for (Test test : findAllTestCasesRuntime()) {
      suite.addTest(test);
    }
    return suite;
  }
}

Эквивалентный код JUnit 4 будет:

import org.junit.runners.AllTests;
import junit.framework.TestSuite;
import junit.framework.Test;

@RunWith(AllTests.class)
public final class MasterTester {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    for (Test test : findAllTestCasesRuntime()) {
      suite.addTest(test);
    }
    return suite;
  }
}

Ответ 4

Я не уверен, что делает команда gatherTestClasses(), но пусть он возвращает некоторые тесты, когда ОС - это Linux и разные тесты, когда ОС - это Windows. Вы можете воспроизвести это в JUnit 4.4 с помощью assumptions:

@Test
public void onlyOnLinux() {
    assumeThat(getOS(), is(OperatingSystem.LINUX));
    // rest of test
}

@Test
public void onlyOnWindows() {
    assumeThat(getOS(), is(OperatingSystem.WINDOWS));
    // rest of test
}

@Test
public void anyOperatingSystem() {
    // just don't call assumeThat(..)
}

Реализация getOS() и OperatingSystem является вашим пользовательским кодом.

Ответ 5

Вот полный пример того, как это реализовать. он объединяет два класса testCase и один набор.

  • ExampleInstrumentedTest:

    import android.support.test.rule.ActivityTestRule;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    public class ExampleInstrumentedTest {
    
    
        @Rule
        public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @Test
        public void checkInputs() throws Exception {
    
        }
    }
    
  • ExampleInstrumentedTest2:

    import android.support.test.rule.ActivityTestRule;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    public class ExampleInstrumentedTest2 {
    
    
        @Rule
        public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @Test
        public void checkInputs() throws Exception {
    
        }
    }
    
  • ExampleInstrumentedSuite:

    import junit.framework.TestSuite;
    
    import org.junit.runner.RunWith;
    import org.junit.runners.AllTests;
    
    @RunWith(AllTests.class)
    public class ExampleInstrumentedSuite {
    
        public static TestSuite suite() {
            TestSuite suite = new TestSuite();
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest.class));
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest2.class));
            return suite;
        }
    }
    

Обратите внимание, что вы должны использовать @RunWith(JUnit4.class) вместо стандартного @RunWith(AndroidJUnit4.class) в классе TestCase