簡體   English   中英

務實地允許用戶選擇將運行哪些 JUnit 測試類

[英]Pragmatically allow User to pick which JUnit Test Classes will be run

我正在嘗試將類列表作為參數傳遞。 (我可以這樣做嗎?)我正在使用 JUnit 和 Selenium,我有 JUnit 測試類由 JUnit 測試套件類調用,使用@SuiteClasses()並且該測試套件類由包含main()的類調用。 我的想法是允許用戶從主類中選擇 JUnit 類,這些類將存儲在某種列表中。 調用要運行的 JUnit 測試類的測試套件將使用該列表並調用那些 JUnit 類。


原始代碼:調用應該運行(工作)的 JUnit 測試類的測試套件類 ⬇

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ TestCase1.class, TestCase2.class})

public class AllTests {

}

我正在嘗試將其更改為類似 ⬇

@SuiteClasses(runnerClass.classesToTest)

在跑步課程中,我會有這樣的事情。 我在想,我可以從 prop 文件中提取類的名稱,並允許用戶選擇將哪些類添加到變量classesToTest

public class runnerClass {    
   public static Class<?>[] classesToTest = { testCase1.class, testCase2.class };
   public static void main(String[] args) {
      ...
   }
}

當我嘗試做這樣的事情時,我收到這個錯誤 ⬇

注釋屬性 Suite.SuiteClasses.value 的值必須是類文字

@SuiteClasses() 的 JavaDoc


所以問題是,我可以做這個工作嗎? classesToTest錯誤地創建了classesToTest變量?

我在 JUnit 框架中找不到任何解決方案,所以我寫了一個快速而骯臟的測試運行程序。 它只是調用所有用@Test 注釋的方法,甚至是不可訪問的方法(以防萬一)。

它不適用於任何包含 UnitTest 結果顯示工具的 IDE。

它的用法如下:

public static void main(String[] args) {
    Runner run = new Runner(TestCase.class, TestCase2.class);
    for(Exception e : run.runUnchecked()) {
        System.err.println(e.getCause());
    }
}

您可以將類作為可變參數或普通數組傳遞,兩者都可以使用。 Runner 將返回測試的異常列表。 如果測試失敗,則拋出異常,或者是導致失敗的異常,或者如果斷言失敗,則拋出AssertionFailedError 您可以使用e.getCause()輕松打印一行描述,這將顯示如下消息: org.opentest4j.AssertionFailedError: expected: <1> but was: <2>

我的示例代碼適用於 JUnit Jupiter 測試,您可以通過更改在 Runner 類中導入的Test類來調整它。 這必須是相同的,用於您的測試用例。

這是代碼

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;

/**
 * A simple JUnit Test Case Runner, which can dynamically call TestCases by
 * their class.
 * 
 * @author Alexander Daum
 *
 */
public class Runner {
    private Class<?>[] testCases;

    public Runner(Class<?>... testCases) {
        this.testCases = testCases;
    }

    /**
     * Run all TestCases given in the constructor of this Runner.
     * 
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public List<Exception> run()
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
        List<Exception> testErrors = new ArrayList<>();
        for (Class<?> testClazz : testCases) {
            Object testCase = testClazz.newInstance();
            Method[] methods = testClazz.getDeclaredMethods();
            methods = Arrays.stream(methods).filter(m -> m.isAnnotationPresent(Test.class)).toArray(Method[]::new);
            for (Method m : methods) {
                m.setAccessible(true);
                try {
                    m.invoke(testCase);
                } catch (InvocationTargetException e) {
                    testErrors.add(e);
                }
            }
        }
        return testErrors;
    }

    /**
     * The same as {@link Runner#run()}, but all exceptions are wrapped in
     * RuntimeException, so no try catch is neccessary, when Errorhandling is not
     * required
     */
    public List<Exception> runUnchecked() {
        try {
            return run();
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM