TestNG 中使用 Guice 来进行依赖注入
Posted huyuchengus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TestNG 中使用 Guice 来进行依赖注入相关的知识,希望对你有一定的参考价值。
Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。
Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter方法)进行注入。
Guice采用Java加注解的方式进行托管对象的配置,充分利用IDE编译器的类型安全检查功能和自动重构功能,使得配置的更改也是类型安全的。
Guice提供模块对应的抽象module,使得架构和设计的模块概念产物与代码中的module类一一对应,更加便利的组织和梳理模块依赖关系,利于整体应用内部的依赖关系维护,而其他IOC框架是没有对应物的。
此外,借助privateModule的功能,可以实现模块接口的明确导出和实现封装,使得支持多数据源这类需求实现起来异常简单。
定义一个 Guice Module
这个 Guice Model 会实现 Module 接口。
然后对需要注入的类进行绑定。
绑定的语句在这里:
binder.bind(TestConfigStorage.class).toInstance(config);
binder.bind(WeChatOfficialAccountService.class).toInstance(weChatOfficialAccountService);
binder.bind(WeChatMsgService.class).toInstance(weChatMsgService);
测试中使用
因为我们需要在测试中使用,所以我们会使用 testNG 的 Guice 注解。
使用下面的语句直接注入到模块中。
然后把需要的服务,注入进来就可以了。
@Inject
protected WeChatOfficialAccountService wxService;
是不是非常简单。
相对 Junit 测试框架来说,TestNG 使用 Guice 更加方便。
如何在 Junit 中使用 Guice ,请参考文章:Junit 5 如何使用 Guice DI 中的内容。
https://www.ossez.com/t/testng-guice/14396
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 |
---|---|---|---|---|---|
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 |
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之依赖注入,就分享到这里。
以上是关于TestNG 中使用 Guice 来进行依赖注入的主要内容,如果未能解决你的问题,请参考以下文章