TestNG进阶玩法:Beanshell

常见的TestNG玩法,在网络上随意可见,今天在Istanbul团队里发现了他们的新玩法: Beanshell
先贴下beanshell在xml的配置示例,它可以通过一段脚本或者代码来自定义需要执行的测试用例,非常灵活。

TestNG里的Beanshell长什么样子?




   
      
         
            
         
      
      
         
      
   

先解释下这里beanshell做了什么,它先导入(import)了一个工具包,然后调用了这个工具包里的方法TestToExecuteMethodSelector.check(method, testngMethod); 其中这两个参数,根据官网上的解释:

  • java.lang.reflect.Method method: the current test method.
  • org.testng.ITestNGMethod testngMethod: the description of the current test method.

如何自定义实现Beanshell

到这里,概念还有点抽象,可以具体看看上面Beanshell代码TestToExecuteMethodSelector.check(method, testngMethod)做了什么?

public class TestToExecuteMethodSelector {
    private static LogManager logger = new LogManager();

    public static boolean check(final Method method, final ITestNGMethod testngMethod) throws IOException {

        if (method.isAnnotationPresent(AutomatedTest.class)) {
            AutomatedTest automatedTestAnnotation = method.getAnnotation(AutomatedTest.class);
            return selector(automatedTestAnnotation.workItemId(), method, testngMethod);
        } else {
            return false;
        }

    }

    private static boolean selector(final int Id, final Method method, final ITestNGMethod testngMethod)
            throws IOException {

        final List workItemIdList = new ArrayList();
        final ClassPathResource resource = new ClassPathResource("testToRun");
        final InputStream inputStream = resource.getInputStream();
        final InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
        final BufferedReader reader = new BufferedReader(streamReader);
        for (String line; (line = reader.readLine()) != null;) {
            if (line.trim() != "" && line.trim() != null) {
                try {
                    workItemIdList.add(Integer.parseInt(line.trim()));
                } catch (NumberFormatException e) {
                    logger.logInfo("Unknown character found in testToRun text file.");
                } catch (Exception e) {
                    logger.logInfo("An exception occured while parsing line to number.");
                    e.printStackTrace();
                }
            }
        }

        return workItemIdList.contains(Id) && testngMethod.getEnabled();
    }
}

代码里有testToRun的resource文件,以及AutomatedTest这个注解。
为了更好的理解,先看看testng的测试用例代码。可以看到,除了@Test,还增加了@AutomatedTest这个自定义注解,其中workItemId表明用例的id号,它可能是Jira里的一个数字。通过method.getAnnotation(AutomatedTest.class),我们可以得到AutomatedTest注解上的workItemId值。

    @Test(enabled = false)
    @AutomatedTest(state = ImplementationState.IMPLEMENTED, workItemId = 1)
    public void testDocumentWithFileType() throws Exception {
        //测试用例执行主体:
        ...
        logManager.logTestStepVerify("Return code is SC_CREATED");
        ...


    }

所以,我们可以在testToRun的文件里,定义这个workItemId,以达到灵活执行指定用例的目的。譬如,testToRun可以定义如下,这表示我这次需要执行id为1,23,45的这三个用例。

1
23
45

回到Xml定义的beanshell脚本, 很明显它的整个过程是:TestNG会为你定义好的里每个标注了注解@Test方法执行一次你的beanshell代码。到这里的具体示例实现就是,TestNG每访问到@Test的方法,都会去获取workItemId的值,看看这个workItemId是否存在在testToRun这个list里面, 以及这个测试用例是否是enabled状态(即,@Test注解参数里enabled是true还是false),要同时满足这两个条件。

return workItemIdList.contains(Id) && testngMethod.getEnabled();

可以看出,虽然1这个用例在testToRun里面定义了,但是由于enabled = false,所以,这个1用例是不会被执行的。

附加

为了故事的完整性,再附上上面代码里提到的AutomatedTest注解。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutomatedTest {
    int workItemId();

    ImplementationState state();

    boolean blocked() default false;
}

其中,ImplementationState是表明这个用例是否已经实现完成可用于执行?还是处于planned状态?

public enum ImplementationState {
    
    PLANNED, IMPLEMENTED

}

你可能感兴趣的:(TestNG进阶玩法:Beanshell)