TestNG + Mockito + PowerMock - verifyStatic() does not work

↘锁芯ラ 提交于 2020-01-09 11:22:29

问题


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.


回答1:


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 statics. 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 { ... }



回答2:


Since this page is highly ranked in search results, I just wanted to add a few more things to the helpful documentation Stephen already wrote about. I just successfully migrated a JUnit test case to TestNG, after initially encountering some issues. I found that you can either do the suite.xml mods, or do it "programmatically", but it's not necessary to do both.

For doing it programmatically, the @ObjectFactory method did not work me, but subclassing PowerMockTestCase did. Here is my sample code:

import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.annotations.Test;

@PrepareForTest(Pokeball.class)
public class PokeballTestTestNG extends PowerMockTestCase {
// Did not work for me
// @ObjectFactory
//    public IObjectFactory getObjectFactory() {
//        return new org.powermock.modules.testng.PowerMockObjectFactory();
//    }

    @Test
    public void test1() throws Exception {
        PowerMockito.spy(Pokeball.class);

        Pokeball.getNetworkMessage();
        Pokeball.getNetworkMessageLang(42);
        Pokeball.getNetworkMessageLang(42);

        PowerMockito.verifyStatic(); //verify one time invocation (default), passes
//        PowerMockito.verifyStatic(Mockito.times(11)); //fails
        Pokeball.getNetworkMessage(); //need to call the method per PowerMock operation - actual test is done here - Exception thrown here upon failure

        PowerMockito.verifyStatic(Mockito.times(2));
        Pokeball.getNetworkMessageLang(42);
    }
}

EDIT: the pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>myG</groupId>
    <artifactId>myTestDouble</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <powermock.version>1.7.0</powermock.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.8.9</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!--JUnit-->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>

        <!--TestNG-->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-testng</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>

        <!--Both TestNG & JUnit-->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito2</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
</project>


来源:https://stackoverflow.com/questions/35801550/testng-mockito-powermock-verifystatic-does-not-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!