我只想在布尔标志为 true 时在 TestNg 中调用 @Test,并注意我不想使用 SkipException

问题描述 投票:0回答:1

我正在使用 TestNg 进行测试自动化。我想仅当某个标志为 true 时才启用测试。

例如

布尔值 isEnabled = true;

看到@Test的启用属性无法实现,因为它不接受变量。

而且我不想使用 SkipException

我尝试使用一些监听器,但没有成功。

java testng testng.xml testng-annotation-test
1个回答
0
投票

您应该能够构建一个利用

org.testng.IMethodInterceptor
的 TestNG 侦听器并完成此任务。

一些事实:

  • 有一个名为
    org.testng.IMethodInterceptor
    的 TestNG 侦听器,在测试方法开始运行之前由 TestNG 调用,其中,您可以从执行计划中添加/删除一个或多个
    @Test
    方法。
  • 有一个名为
    org.testng.IAlterSuiteListener
    的 TestNG 侦听器,它允许您修改已解析的
    <suite>
    标签,并且您可以在其中添加/修改
    <test>
    标签。

遵循的步骤:

  • 构建一个实现
    IMethodInterceptor
    IAlterSuiteListener
  • 的 TestNG 监听器
  • IAlterSuiteListener
    的实现基本上会查询系统属性(通过
    -D
    JVM 参数传递的属性)并查找名为
    exclude_methods
    的系统属性,如果找到此属性,那么它将更改所有
     <suite>
    标签并以编程方式向其添加名为
    <parameter>
    exclude_methods
  • IMethodInterceptor
    的实现基本上会解析
    <suite>
    参数并查找名为
    exclude_methods
    的参数,如果找到,它会将其拆分为
    n
    值(因为我们将允许该值是逗号分隔),对于每个分割值,它将对正则表达式知道的任何元字符进行转义序列,以及它尝试与输入排除列表进行模式匹配的转义序列方法名称,从而修剪方法列表。

您可以使用以下机制之一连接此侦听器:

  • 通过
    @Listener
    注释(或)
  • 通过套件文件中的
    <listener>
    标签(或)
  • 通过服务加载机制。

有关 TestNG 监听器接线的更多详细信息,请参阅官方文档

要了解有关方法拦截器的更多信息,请参阅此处

注意: 确保您使用的是最新发布的 TestNG 版本

v7.10.2

import org.testng.*;
import org.testng.xml.XmlSuite;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SimpleMethodSelector implements IMethodInterceptor, IAlterSuiteListener {
    private static final List<Pattern> patterns = new ArrayList<>();
    public static final String EXCLUDE_METHODS = "exclude_methods";

    @Override
    public void alter(List<XmlSuite> suites) {
        //Let's check if there were any methods provided to us to be ignored via the JVM argument
        String excludeMethods = System.getProperty(EXCLUDE_METHODS, "");
        if (!excludeMethods.isEmpty()) {
            //If there were some patterns (can be comma separated) then lets add this
            //as a parameter into the <suite> tag.
            suites.forEach(it -> it.getParameters().put(EXCLUDE_METHODS, excludeMethods));
        }
    }

    @Override
    public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
        buildExclusionPatterns(context);
        if (patterns.isEmpty()) {
            //If there were no patterns to be considered, then it means that the user wants to execute everything
            return methods;
        }
        return methods.stream()
                .filter(it -> !shouldExcludeMethod(it.getMethod()))
                .collect(Collectors.toList());
    }

    private static boolean shouldExcludeMethod(ITestNGMethod itm) {
        return patterns.stream()
                .anyMatch(
                        pattern -> methodNamesToConsider(itm)
                                .anyMatch(name -> pattern.matcher(name).matches())
                );
    }

    private static Stream<String> methodNamesToConsider(ITestNGMethod itm) {
        return Stream.of(
                itm.getQualifiedName(),//Match fully qualified method name (or)
                itm.getMethodName() //Match just method name without fully qualified class name
        );
    }

    private static void buildExclusionPatterns(ITestContext context) {
        if (!patterns.isEmpty()) {
            //If we already built the pattern once, then lets not doing again and again
            //because this method will be called for each and every test method within a <test> tag
            return;
        }

        //Check if the current <test> tag contains the parameter "exclude_methods"
        String excludedMethods = context.getCurrentXmlTest().getParameter(EXCLUDE_METHODS);
        if (Optional.ofNullable(excludedMethods).orElse("").isEmpty()) {
            //If there were no methods to be excluded, then there's nothing to process.
            //Lets return
            return;
        }
        for (String method : excludedMethods.split(",")) {
            String escapedMethod = escape(method); //Escape sequence all the regex special characters
            System.err.println("Working with pattern " + escapedMethod);
            Pattern pattern = Pattern.compile(escapedMethod, Pattern.DOTALL);
            patterns.add(pattern);
        }
    }

    private static String escape(String text) {
        return text.chars()
                .mapToObj(SimpleMethodSelector::asString)
                .collect(Collectors.joining());
    }

    //Refer https://jenkov.com/tutorials/java-regex/index.html#metacharacters for more details
    private static final List<Character> META_CHARACTERS = List.of(
            '<', '>', '(', ')', '[', ']', '{', '}', '\\', '^', '-', '=',
            '$', '!', '|', '?', '*', '+', '.'
    );

    private static String asString(int it) {
        return META_CHARACTERS.contains((char) it) ? "\\\\" + (char) it : Character.toString(it);
    }
}

示例测试用例如下所示:

import org.testng.Reporter;
import org.testng.annotations.Test;

public class SampleTestCase {

    @Test
    public void a() {
        System.err.println(Reporter.getCurrentTestResult().getMethod().getQualifiedName() + "()");
    }

    @Test
    public void b() {
        System.err.println(Reporter.getCurrentTestResult().getMethod().getQualifiedName() + "()");
    }

    @Test
    public void c() {
        System.err.println(Reporter.getCurrentTestResult().getMethod().getQualifiedName() + "()");
    }
}

这是一个示例套件文件

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="78547470_suite" verbose="2">
    <parameter name="exclude_methods" value=""/>
    <test name="78547470_test">
        <classes>
            <class name="com.rationaleemotions.so.qn78547470.SampleTestCase"/>
        </classes>
    </test>
</suite>

这是通过 IntelliJ 运行此测试时的运行配置

enter image description here

这是执行输出

...
... TestNG 7.10.2 by Cédric Beust ([email protected])
...

Working with pattern \\*b\\*
com.rationaleemotions.so.qn78547470.SampleTestCase.a()
com.rationaleemotions.so.qn78547470.SampleTestCase.c()
PASSED: com.rationaleemotions.so.qn78547470.SampleTestCase.c
PASSED: com.rationaleemotions.so.qn78547470.SampleTestCase.a

===============================================
    78547470_test
    Tests run: 3, Failures: 0, Skips: 0
===============================================
© www.soinside.com 2019 - 2024. All rights reserved.