Java自动化测试框架-09 - TestNG之依赖注入篇 (详细教程)

1.-依赖注入

TestNG支持两种不同类型的依赖项注入:本机(由TestNG本身执行)和外部(由诸如Guice的依赖项注入框架执行)。

1.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批注关闭注入:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
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 
BeforeSuiteYesNoNoNoNo
BeforeTestYesYesNoNoNo
BeforeGroupsYesYesNoNoNo
BeforeClassYesYesNoNoNo
BeforeMethodYesYesYesYesYes
TestYesNoNoNoNo
DataProviderYesNoYesNoNo
AfterMethodYesYesYesYesYes
AfterClassYesYesNoNoNo
AfterGroupsYesYesNoNoNo
AfterTestYesYesNoNoNo
AfterSuiteYesNoNoNoNo

1.2-Guice依赖注入

如果您使用Guice,TestNG为您提供了一种简单的方法,即可通过Guice模块注入测试对象:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
@Guice(modules = GuiceExampleModule.class)
public class GuiceTest extends SimpleBaseTest {
 
  @Inject
  ISingleton m_singleton;
 
  @Test
  public void singletonShouldWork() {
    m_singleton.doSomething();
  }
 
}

在此示例中,预计GuiceExampleModule会将接口ISingleton绑定到一些具体的类:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
public class GuiceExampleModule implements Module {
 
  @Override
  public void configure(Binder binder) {
    binder.bind(ISingleton.class).to(ExampleSingleton.class).in(Singleton.class);
  }
 
}

如果需要更大的灵活性来指定应使用哪些模块实例化测试类,则可以指定模块工厂:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
@Guice(moduleFactory = ModuleFactory.class)
public class GuiceModuleFactoryTest {
 
  @Inject
  ISingleton m_singleton;
 
  @Test
  public void singletonShouldWork() {
    m_singleton.doSomething();
  }
}

模块工厂需要实现接口IModuleFactory:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
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套件参数,您将获得更大的灵活性和Guice功能。 guice-stage可让您选择用于创建父注射器的Stage。默认值是DEVELOPMENT。其他允许的值为PRODUCTION和TOOL。这是在test.xml文件中定义父模块的方法:

<suite parent-module="com.example.SuiteParenModule" guice-stage="PRODUCTION">
</suite>

对于给定的套件,TestNG将只创建一次此模块。还将使用该模块获取特定于测试的Guice模块和模块工厂的实例,然后将为每个测试类创建子注入器。通过这种方法,您可以在父模块中声明所有公共绑定,也可以在模块和模块工厂中注入在父模块中声明的绑定。这是此功能的示例:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
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);
  }
}
/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
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>
/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
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此配置可确保您使用同一会话实例运行该套件中的所有测试,MyContextImpl对象每个套件仅创建一次,这使您可以为套件中的所有测试配置通用环境状态。

2.-侦听方法调用

每当TestNG即将调用测试(用@Test注释)或配置(用@Before或@After注释中的任何一个注释)方法时 ,侦听器IInvokedMethodListener都会通知您。您需要实现以下接口:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
public interface IInvokedMethodListener extends ITestNGListener {
  void beforeInvocation(IInvokedMethod method, ITestResult testResult);
  void afterInvocation(IInvokedMethod method, ITestResult testResult);
}

并将其声明为侦听器,如有关TestNG侦听器的部分所述。 

3.-覆盖测试方法

TestNG允许您重写并可能跳过测试方法的调用。一个有用的例子是,如果您需要使用特定的安全管理器来测试方法。您可以通过提供实现IHookable的侦听器来实现此目的。

这是JAAS的示例:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
public class MyHook implements IHookable {
  public void run(final IHookCallBack icb, ITestResult testResult) {
    // Preferably initialized in a @Configuration method
    mySubject = authenticateWithJAAs();
    
    Subject.doAs(mySubject, new PrivilegedExceptionAction() {
      public Object run() {
        icb.callback(testResult);
      }
    };
  }
}

4.-变更套件(或)测试

有时,您可能只需要在运行时更改套件xml中的套件(或)测试标签,而不必更改套件文件的内容。

一个典型的例子就是尝试利用现有的套件文件,并尝试使用它在“被测应用程序”上模拟负载测试。至少您最终将多次复制<test>标记的内容,并创建一个新的套件xml文件并使用。但这似乎并没有太大的规模。

TestNG允许您在运行时通过侦听器更改套件xml文件中的套件(或)测试标签。您可以通过提供实现IAlterSuiteListener的侦听器来实现此目的。请参考“ 监听器”部分以了解监听器。

这是一个示例,显示套件名称在运行时如何更改:

/**
 * @author 北京-宏哥
 * 
 * Java自动化测试框架-09 - TestNG之 依赖注入篇
 *
 * 2019年11月8日
 */
public class AlterSuiteNameListener implements IAlterSuiteListener {
 
    @Override
    public void alter(List<XmlSuite> suites) {
        XmlSuite suite = suites.get(0);
        suite.setName(getClass().getSimpleName());
    }
}

只能通过以下两种方式之一添加此侦听器:

通过套件xml文件中的<listeners>标记。
通过服务加载程序
不能使用@Listeners批注将此侦听器添加到执行中。

5.-小结

  好了,今天关于TestNG之依赖注入,就分享到这里。

相关推荐