TestNG支持两种不同类型的依赖项注入:本地(由TestNG本身执行)和外部(由诸如Guice(Google依赖注入框架)之类的依赖项注入框架执行)。
1. 本地依赖注入
TestNG允许在方法中声明其他参数。发生这种情况时,TestNG将自动用正确的值填充这些参数。依赖注入可以在以下地方使用:
任何@Before方法或@Test方法都可以声明ITestContext类型的参数。 任何@AfterMethod方法都可以声明ITestResult类型的参数,该参数将反映刚刚运行的测试方法的结果。 任何@Before和@After方法(@BeforeSuite和@AfterSuite除外)都可以声明XmlTest类型的参数,该参数包含当前的<test>标记。 任何@BeforeMethod(和@AfterMethod)都可以声明java.lang.reflect.Method类型的参数。此参数将接收此@BeforeMethod完成之后(或在为@AfterMethod运行的方法之后)将调用的测试方法。 任何@BeforeMethod都可以声明Object[]类型的参数。此参数将接收测试方法的参数的列表,该列表可以由TestNG注入,例如java.lang.reflect.Method或来自@DataProvider。 任何@DataProvider都可以声明ITestContext或java.lang.reflect.Method类型的参数。后一个参数将接收将要调用的测试方法。
可以使用@NoInjection批注关闭注入:
public class NoInjectionTest { @DataProvider(name = "provider") public Object[][] provide() throws Exception { return new Object[][] { { CC.class.getMethod("f") } }; } @Test(dataProvider = "provider") public void withoutInjection(@NoInjection Method m) { Assert.assertEquals(m.getName(), "f"); } @Test(dataProvider = "provider") public void withInjection(Method m) { Assert.assertEquals(m.getName(), "withInjection"); } }
下表总结了可以为TestNG注解本地注入的各种参数类型:
Annotation | ITestContext | XmlTest | Method | Object[] | ITestResult |
BeforeSuite | Yes | No | No | No | No |
BeforeTest | Yes | Yes | No | No | No |
BeforeGroups | Yes | Yes | No | No | No |
BeforeClass | Yes | Yes | No | No | No |
BeforeMethod | Yes | Yes | Yes | Yes | Yes |
Test | Yes | No | No | No | No |
DataProvider | Yes | No | Yes | No | No |
AfterMethod | Yes | Yes | Yes | Yes | Yes |
AfterClass | Yes | Yes | No | No | No |
AfterGroups | Yes | Yes | No | No | No |
AfterTest | Yes | Yes | No | No | No |
AfterSuite | Yes | No | No | No | No |
2. 外部依赖注入
如果使用的是Guice,TestNG提供了一种使用Guice模块注入测试对象的简便方法:
@Guice(modules = GuiceExampleModule.class) public class GuiceTest extends SimpleBaseTest { @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_singleton.doSomething(); } }
在这个示例中,GuiceExampleModule会将接口ISingleton绑定到一些具体的类:
public class GuiceExampleModule implements Module { @Override public void configure(Binder binder) { binder.bind(ISingleton.class).to(ExampleSingleton.class).in(Singleton.class); } }
如果希望在指定应使用哪些模块实例化测试类时更灵活,则可以指定一个模块工厂:
@Guice(moduleFactory = ModuleFactory.class) public class GuiceModuleFactoryTest { @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_singleton.doSomething(); } }
模块工厂需要实现接口IModuleFactory:
public interface IModuleFactory { /** * @param context The current test context * @param testClass The test class * * @return The Guice module that should be used to get an instance of this * test class. */ Module createModule(ITestContext context, Class<?> testClass); }
说明:工厂将通过TestNG实例化测试上下文和测试类的实例。createModule方法返回一个Guice模块,该模块需要知道如何实例化此测试类。可以使用测试上下文找到有关环境的更多信息,例如在testng.xml中指定的参数等。
通过父模块和guice-stage suite参数,可以更灵活的结合Guice功能进行使用。guice-stage允许选择用于创建父类注入的Stage。默认值是DEVELOPMENT。其他允许的值为PRODUCTION和TOOL。是在test.xml文件中定义父模块的方法:
<suite parent-module="com.example.SuiteParenModule" guice-stage="PRODUCTION"> </suite>
对于给定的suite集,TestNG将仅创建一次该模块,还将使用该模块获取特定测试的Guice模块和模块工厂的实例,然后将为每个测试类创建子注入器。通过这种方法,您可以在父模块中声明所有公共绑定,也可以在模块和模块工厂中注入在父模块中声明的绑定。 以下是相关示例:
package com.example; public class ParentModule extends AbstractModule { @Override protected void conigure() { bind(MyService.class).toProvider(MyServiceProvider.class); bind(MyContext.class).to(MyContextImpl.class).in(Singleton.class); } } package com.example; public class TestModule extends AbstractModule { private final MyContext myContext; @Inject TestModule(MyContext myContext) { this.myContext = myContext } @Override protected void configure() { bind(MySession.class).toInstance(myContext.getSession()); } } <suite parent-module="com.example.ParentModule"> </suite> package com.example; @Test @Guice(modules = TestModule.class) public class TestClass { @Inject MyService myService; @Inject MySession mySession; public void testServiceWithSession() { myService.serve(mySession); } }
说明:如上图所示,ParentModule为MyService和MyContext类声明了绑定。然后使用构造函数注入将MyContext注入到TestModule类中,该类也声明对MySession的绑定。然后将测试XML文件中的parent-module设置为ParentModule类,这样来启用在TestModule中的注入。
然后在TestClass中,会看到两次注入:* MyService-绑定取自ParentModule 、* MySession-绑定取自TestModule。此配置可确保在suite中的所有测试都将在同一会话实例上运行,MyContextImpl对象每个suite仅创建一次, 这可以为suite中的所有测试配置通用的环境状态。
欢迎多多交流~