TestNG + Mockito + PowerMock - verifyStatic() 不起作用
我是新的 TestNG 和一般的单元测试.我将 TestNG 6.9.6 与 Mockito 1.10.19 和 PowerMock 1.6.4 一起使用.我想验证 MyService
类中的 myMethod()
方法是否在内部使用正确的参数调用静态方法 Util.myStaticMethod
.由于 Mockito 本身不支持对静态方法的验证,因此我将 PowerMock 与它一起使用.我的测试类如下所示:
公共类 MyTest{私人的我的服务我的服务;@Captor ArgumentCaptor<字符串>参数捕捉器;@BeforeMethod公共无效设置(){MockitoAnnotations.initMocks( 这个 );我的服务 = 新的我的服务();}@测试@PrepareForTest(MyService.class)公共无效我的测试(){PowerMockito.mockStatic(Util.class);myService.myMethod("arg");PowerMockito.verifyStatic(10);Util.myStaticMethod(anyString());}}
这个测试预计会失败,因为 myMethod
只调用了一次静态方法 Util.myStaticMethod()
.但是当我运行测试时,它总是通过,无论我将什么值传递给 PowerMockito.verifyStatic()
.
另外,如果我在这个类中编写另一个测试方法然后运行测试,我会得到以下错误
org.mockito.exceptions.misusing.UnfinishedVerificationException:此处缺少验证(模拟)的方法调用:->在 mypackage.MyTest.myTest(MyTest.java:21)正确验证示例:验证(模拟).doSomething()此外,此错误可能会出现,因为您验证了以下任一方法:final/private/equals()/hashCode() 方法.这些方法*不能*被存根/验证.不支持在非公共父类上声明的模拟方法.在 mypackage.MyTest.myTest.setup(MyTest.java:10)结果 :失败的测试:MyTest.setup:10 未完成验证缺少对版本的方法调用...测试运行:3,失败:1,错误:0,跳过:1
它在 verifyStatic()
方法处失败,这让我认为 verifyStatic() 方法需要更多我没有提供的东西.此外,它表示测试总数为 3,而在这种情况下,我只有两种测试方法.
任何帮助将不胜感激.
按照建议,我尝试将 MyUtil
类放在 @PrepareForTest
注释中,它仍然给出相同的错误.
好的,我认为这是非常特定于 TestNG 配置的,因为所有 JUnit 示例都是开箱即用"的!
阅读 PowerMock GitHub 站点上的 this 链接,该链接描述了有关如何将 TestNG 与 PowerMock 一起使用.使用此示例代码在此处描述了您验证对模拟 static
方法的调用的场景:
@PrepareForTest(IdGenerator.class)公共类 MyTestClass {@测试公共无效demoStaticMethodMocking()抛出异常{模拟静态(IdGenerator.class);when(IdGenerator.generateNewId()).thenReturn(2L);新的 ClassUnderTest().methodToTest();//可选地验证静态方法是否被实际调用验证静态();IdGenerator.generateNewId();}}
然后是这个信息块:
<块引用>为此,您需要告诉 TestNG 使用 PowerMock 对象工厂
这是使用 TestNG XML 配置或在测试代码本身中完成的.为了完整起见,我已将上述 URL 中给出的选项复制到下方.FWIW 我扩展了 PowerMockTestCase
并且验证按您的预期工作.
最后,不要忘记 @PrepareForTest
正确的类 - 即包含要模拟的 static
方法的类,正如@Bax 指出的那样 这里.
作为进一步的提示(您可能已经知道,但无论如何这里值得一提),因为您没有使用 Mockito 来模拟对象,所以可以安全地删除 MockitoAnnotations.initMocks(this)
.
完成所有这些工作后,您可能还想考虑是否使用 'Black Magic' 像 Powermock 这样的工具实际上在您的设计中暴露了 代码异味?特别是因为看起来包含 static
方法的类在您的所有权之下.这意味着您可以使用不使用 static
的替代设计.我强烈推荐 Michael Feathers 的书Working Effectively with Legacy Code,它可能会改变你的整个软件设计和测试方法......
祝你好运!
<块引用>配置 TestNG 以使用 PowerMock 对象工厂
使用套件.xml
在您的 suite.xml 中,在套件标签中添加以下内容:object-factory="org.powermock.modules.testng.PowerMockObjectFactory"
例如
<套件名称="dgf" verbose="10"object-factory="org.powermock.modules.testng.PowerMockObjectFactory"><测试名称="dgf"><类><类名="com.mycompany.Test1"/><类名="com.mycompany.Test2"/></类></测试>
如果您使用的是 Maven,您可能需要向 Surefire 指出该文件:
<插件><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><配置><suiteXmlFiles><suiteXmlFile>suite.xml</suiteXmlFile></suiteXmlFiles></配置></插件>
以编程方式
将这样的方法添加到您的测试类中:
@ObjectFactory public IObjectFactory getObjectFactory() {返回新的 org.powermock.modules.testng.PowerMockObjectFactory();}
或者为了安全起见,您也可以从 PowerMockTestCase
进行扩展:
@PrepareForTest(IdGenerator.class)公共类 MyTestClass 扩展 PowerMockTestCase { ... }
I am new TestNG and unit-testing in general. I am using TestNG 6.9.6 with Mockito 1.10.19 and PowerMock 1.6.4. I want to verify whether the myMethod()
method in MyService
class internally calls the static method Util.myStaticMethod
with the correct arguments. Since verification of static methods is not natively supported in Mockito, I am using PowerMock along with it. My Test class is shown below:
public class MyTest
{
private MyService myService;
@Captor ArgumentCaptor<String> argCaptor;
@BeforeMethod
public void setup()
{
MockitoAnnotations.initMocks( this );
myService = new MyService();
}
@Test
@PrepareForTest(MyService.class)
public void myTest()
{
PowerMockito.mockStatic(Util.class);
myService.myMethod("arg");
PowerMockito.verifyStatic(10);
Util.myStaticMethod(anyString());
}
}
This test is expected to fail, as myMethod
calls the static method Util.myStaticMethod()
only once. But when i run the test, it always passes, no matter what value i pass to PowerMockito.verifyStatic()
.
Also, if I write another test method in this class and then run the test, I get the following error
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at mypackage.MyTest.myTest(MyTest.java:21)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
at mypackage.MyTest.myTest.setup(MyTest.java:10)
Results :
Failed tests:
MyTest.setup:10 UnfinishedVerification
Missing method call for ver...
Tests run: 3, Failures: 1, Errors: 0, Skipped: 1
It fails at the verifyStatic()
method, which makes me think that the verifyStatic() method needs something more that i am not providing. Also, it indicates the total number of tests as 3 whereas in this case I have only two test methods.
Any help would be appreciated.
EDIT : As suggested, I tried putting MyUtil
class in the the @PrepareForTest
annotation, it still gives the same error.
OK, I think this is very specific to TestNG configurations, since all of the JUnit examples work 'out of the box'!
Read through this link from the PowerMock GitHub site which describes further detail on how to use TestNG together with PowerMock. Exactly your scenario of verifying calls to mocked static
methods is described there using this example code:
@PrepareForTest(IdGenerator.class) public class MyTestClass { @Test public void demoStaticMethodMocking() throws Exception { mockStatic(IdGenerator.class); when(IdGenerator.generateNewId()).thenReturn(2L); new ClassUnderTest().methodToTest(); // Optionally verify that the static method was actually called verifyStatic(); IdGenerator.generateNewId(); } }
Which is then followed by this nugget of information:
For this to work you need to tell TestNG to use the PowerMock object factory
This is done using either TestNG XML config, or in the test's code itself. For completeness I've copied below the options given at the above URL. FWIW I extended PowerMockTestCase
and the verification worked as you expect.
Finally, don't forget to @PrepareForTest
the correct class - i.e. the class containing the static
methods which you want to mock, as @Bax pointed out here.
As a further hint (which you probably already know about, but worth mentioning here anyway) since you aren't using Mockito to mock objects, MockitoAnnotations.initMocks(this)
can be safely deleted.
Once you've got all this working, you might also like to consider whether the use of 'Black Magic' tools like Powermock is actually exposing code smells in your design? Especially since it looks like the classes containing static
methods are under your ownership. This means you could use an alternative design that doesn't use static
s. I highly recommend Michael Feathers' book Working Effectively with Legacy Code, it might just change your whole approach to software design and testing...
Good luck!
Configure TestNG to use the PowerMock object factory
Using suite.xml
In your suite.xml add the following in the suite tag:
object-factory="org.powermock.modules.testng.PowerMockObjectFactory"
e.g.<suite name="dgf" verbose="10" object-factory="org.powermock.modules.testng.PowerMockObjectFactory"> <test name="dgf"> <classes> <class name="com.mycompany.Test1"/> <class name="com.mycompany.Test2"/> </classes> </test>
If you're using Maven you may need to point out the file to Surefire:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <suiteXmlFiles> <suiteXmlFile>suite.xml</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin>
Programmatically
Add a method like this to your test class:
@ObjectFactory public IObjectFactory getObjectFactory() { return new org.powermock.modules.testng.PowerMockObjectFactory(); }
or to be on the safe side you can also extend from the
PowerMockTestCase
:@PrepareForTest(IdGenerator.class) public class MyTestClass extends PowerMockTestCase { ... }
相关文章