我可以在TestNG测试用例上指定类范围的组吗?
我有一个基类代表TestNG中的数据库测试,我想指定所有从该类扩展的类都属于" db-test"组,但是我发现这似乎是不可能的。我尝试了@Test批注:
@Test(groups = { "db-test" }) public class DBTestBase { }
但是,这是行不通的,因为@Test批注将尝试将一系列方法引入测试中,并且在运行测试时会在eclipse中弹出警告/错误。
所以我尝试禁用测试,因此至少分配了组:
@Test(enabled = false, groups = { "db-test" }) public class DBTestBase { }
但是然后任何@BeforeTest(和其他类似的注释)也被禁用了……这当然不是我想要的。
我想以某种方式将类注释为特定类型的组,但是在TestNG中似乎不太可能。还有其他想法吗?
解决方案
回答
我不确定TestNG的注释继承如何工作,但是本文可能会有所帮助。
实际上,这可能会更好,请看一下牢靠的Groups。
回答
TestNG将运行带有@Test批注的类中的所有公共方法。也许我们可以更改不希望TestNG运行为非公开的方法
回答
我们可以在方法级别指定@Test批注,以实现最大的灵活性。
public class DBTestBase { @BeforeTest(groups = "db-test") public void beforeTest() { System.out.println("Running before test"); } public void method1() { Assert.fail(); // this does not run. It does not belong to 'db-test' group. } @Test(groups = "db-test") public void testMethod1() { Assert.assertTrue(true); } }
这对我们有用吗,还是我从问题中遗漏了一些东西。
回答
在我看来,这是以下代码挑战(社区Wiki帖子):
如何在不使用" aGlobalGroup"组的情况下执行扩展类的所有测试方法:
- 在扩展类本身上指定'aGlobalGroup'组?
- 测试扩展类的非注释公共方法?
第一个答案很简单:
在基类级别上添加一个类TestNG(groups = {" aGlobalGroup"})
该组将适用于Base类和Extended类的所有公共方法。
但是:即使是非testng公共方法(没有TestNG批注)也将包括在该组中。
挑战:避免包括那些非TestNG方法。
@Test(groups = { "aGlobalGroup" }) public class Base { /** * */ @BeforeClass public final void setUp() { System.out.println("Base class: @BeforeClass"); } /** * Test not part a 'aGlobalGroup', but still included in that group due to the class annotation. <br /> * Will be executed even if the TestNG class tested is a sub-class. */ @Test(groups = { "aLocalGroup" }) public final void aFastTest() { System.out.println("Base class: Fast test"); } /** * Test not part a 'aGlobalGroup', but still included in that group due to the class annotation. <br /> * Will be executed even if the TestNG class tested is a sub-class. */ @Test(groups = { "aLocalGroup" }) public final void aSlowTest() { System.out.println("Base class: Slow test"); //throw new IllegalArgumentException("oups"); } /** * Should not be executed. <br /> * Yet the global annotation Test on the class would include it in the TestNG methods... */ public final void notATest() { System.out.println("Base class: NOT a test"); } /** * SubClass of a TestNG class. Some of its methods are TestNG methods, other are not. <br /> * The goal is to check if a group specify in the super-class will include methods of this class. <br /> * And to avoid including too much methods, such as public methods not intended to be TestNG methods. * @author <a href="http://stackoverflow.com/users/6309/vonc">VonC</a> */ public static class Extended extends Base { /** * Test not part a 'aGlobalGroup', but still included in that group due to the super-class annotation. <br /> * Will be executed even if the TestNG class tested is a sub-class. */ @Test public final void anExtendedTest() { System.out.println("Extended class: An Extended test"); } /** * Should not be executed. <br /> * Yet the global annotation Test on the class would include it in the TestNG methods... */ public final void notAnExtendedTest() { System.out.println("Extended class: NOT an Extended test"); } }
回答
答案是通过自定义的org.testng.IMethodSelector:
它的includeMethod()可以排除我们想要的任何方法,例如公共的未注释方法。
但是,要注册自定义Java MethodSelector,必须将其添加到任何TestRunner管理的XMLTest实例中,这意味着我们需要自己的自定义TestRunner。
但是,要构建自定义TestRunner,我们需要通过-testrunfactory选项注册一个TestRunnerFactory。
但是-testrunfactory永远不会被TestNG类考虑...因此我们还需要定义一个自定义的TestNG类:
- 为了覆盖configure(Map)方法,
- 因此我们实际上可以设置TestRunnerFactory
- TestRunnerFactory将为我们构建自定义TestRunner,
- TestRunner,它将为XMLTest实例设置自定义XMLMethodSelector
- XMLMethodSelector将构建自定义IMethodSelector
- IMethodSelector将排除我们选择的任何TestNG方法!
好吧...这是一场噩梦。但这也是一个代码挑战,因此它一定有点挑战;)
DZone片段中提供了所有代码。
像往常一样进行代码挑战:
- 一个Java类(以及很多内部类)
- 将类复制并粘贴到"源/测试"目录中(因为软件包为"测试")
- 运行它(不需要任何参数)
来自Mike Stone的更新:
我将接受这一点,因为这听起来与我最终要完成的工作非常接近,但是我认为我也会补充我所做的。
基本上,我创建了一个Groups批注,其行为类似于Test(和其他)批注的groups属性。
然后,我创建了一个GroupsAnnotationTransformer,它使用IAnnotationTransformer查看所有测试和定义的测试类,然后修改测试以添加组,这与组排除和包含完美配合。
修改构建以使用新的注释转换器,一切都可以完美地工作!
嗯...一个警告是,它没有将组添加到非测试方法中...因为在我这样做的时候,还有另一个注释转换器可以让我们转换任何内容,但是不包括在内在我出于某种原因使用的TestNG中...因此,使我们之前/之后的注释方法始终运行= true是一个好主意...对我来说足够了。
最终结果是我可以做到:
@Groups({ "myGroup1", "myGroup2"}) public class MyTestCase { @Test @Groups("aMethodLevelGroup") public void myTest() { } }
然后,我使用子类化和所有内容使变压器工作。