Mocking objects with Mockito with constructor argument and static classes that do nothing.

15,093 views
Skip to first unread message

Karthik Krishnan

unread,
Feb 3, 2010, 7:26:31 PM2/3/10
to PowerMock
Hi,

In my class under test, I have code snippet which codes something
like this:


Properties p = new Properties();
p.put("mail.smtp.host", smtpHost);

Session session = Session.getDefaultInstance(p, null);
MimeMessage msg = new MimeMessage(session);
msg.setFrom(....)
msg.setTo(...)
msg.setText("...");
msg.setSubject("..");
Transport.send(msg);

I have two questions

1. Is there a way to mock MimeMessage considering that it depends on
session as a constructor argument. PowerMockito#mock(Class<T> class)
accepts only one argument.
2. Transport#send(MimeMessage) has a void return type. To mock void
return types, PowerMockito.doNothing() .when(T)... is used. But T
expects an object not a static class.

Mock code:

/ Mock session classes.
MimeMessage message = PowerMockito.mock(MimeMessage.class);
PowerMockito.doNothing().when(message)
.setFrom(Mockito.isA(InternetAddress.class));
PowerMockito.doNothing().when(message).setRecipient(
Mockito.eq(Message.RecipientType.TO),
Mockito.isA(InternetAddress.class));
PowerMockito.doNothing().when(message).setSubject(Mockito.anyString());
PowerMockito.doNothing().when(message)
.setSentDate(Mockito.any(Date.class));
PowerMockito.doNothing().when(message).setText(Mockito.anyString());
PowerMockito.mockStatic(Transport.class);


Please advise.

Johan Haleby

unread,
Feb 4, 2010, 8:48:31 AM2/4/10
to powe...@googlegroups.com
Hi,

1) Yes you can mock MimeMessage. You should use "whenNew", e.g. whenNew(MimeMessage.class).withArguments(isA(Session.class)).thenReturn(mimeMessageMock); Note that you have to prepare the class that performs "new MimeMessage" and not MimeMessage itself.
2) There are several ways to do this. E.g.
PowerMockito.doNothing().when(Transport.class); Transport.send(msgMock);
  You can also use suppress(method(Transport.class, "send"));

/Johan


--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To post to this group, send email to powe...@googlegroups.com.
To unsubscribe from this group, send email to powermock+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/powermock?hl=en.


Kartik Kumar

unread,
Feb 4, 2010, 7:53:04 PM2/4/10
to powe...@googlegroups.com
Hi Johan,

I tried your suggestion and I am getting an error message that several matching constructors are found. I am using TestNG and Mockito.

Test Code

// Mock session classes.
        MimeMessage message = PowerMockito.mock(MimeMessage.class);
        PowerMockito.whenNew(MimeMessage.class)
                .withArguments(Mockito.isA(Session.class))
                .thenReturn(message);

       // These lines are not executed.

        PowerMockito.doNothing().when(message)
            .setFrom(Mockito.isA(InternetAddress.class));
        PowerMockito.doNothing().when(message).setRecipient(
                Mockito.eq(Message.RecipientType.TO),
                Mockito.isA(InternetAddress.class));
        PowerMockito.doNothing().when(message).setSubject(Mockito.anyString());
        PowerMockito.doNothing().when(message)
                .setSentDate(Mockito.any(Date.class));
        PowerMockito.doNothing().when(message).setText(Mockito.anyString());
        PowerMockito.mockStatic(Transport.class);
        PowerMockito.doNothing().when(Transport.class);

        // Call class under test.
        swEaiEmail eaiEmail = new swEaiEmail();
        eaiEmail.execute("", Collections.EMPTY_LIST, inputFields);
        Transport.send(message);

Error Log

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.invoke(PowerMockTestNGMethodHandler.java:48)
    at swEaiEmailTest_$$_javassist_0.testExecute_criticalPath(swEaiEmailTest_$$_javassist_0.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:644)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:546)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:700)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1002)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:909)
    at org.testng.TestRunner.privateRun(TestRunner.java:618)
    at org.testng.TestRunner.run(TestRunner.java:499)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:332)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:327)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:299)
    at org.testng.SuiteRunner.run(SuiteRunner.java:204)
    at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:915)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:879)
    at org.testng.TestNG.run(TestNG.java:787)
    at AllTests.main(AllTests.java:20)
Caused by: org.powermock.reflect.exceptions.TooManyConstructorsFoundException: Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're refering to.
Matching constructors in class javax.mail.internet.MimeMessage were:
javax.mail.internet.MimeMessage( javax.mail.Folder.class int.class )
javax.mail.internet.MimeMessage( javax.mail.Session.class java.io.InputStream.class )

    at org.powermock.reflect.internal.WhiteboxImpl.throwExceptionWhenMultipleConstructorMatchesFound(WhiteboxImpl.java:1408)
    at org.powermock.reflect.internal.WhiteboxImpl.findUniqueConstructorOrThrowException(WhiteboxImpl.java:904)
    at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.createNewSubsituteMock(DefaultConstructorExpectationSetup.java:69)
    at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.withArguments(DefaultConstructorExpectationSetup.java:48)
    at swEaiEmailTest.testExecute_criticalPath(swEaiEmailTest.java:102)
    at swEaiEmailTest_$$_javassist_0._d2testExecute_criticalPath(swEaiEmailTest_$$_javassist_0.java)
    ... 27 more

Johan Haleby

unread,
Feb 5, 2010, 2:27:48 AM2/5/10
to powe...@googlegroups.com
This means that PowerMock cannot determine the constructor based on the parameters you sent. In these cases (which ought to be quite rare) you need to specify the parameter types as well e.g.
whenNew(MimeMessage.class).withParameterTypes(MyParameterType.class).withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);

/Johan

Kartik Kumar

unread,
Feb 7, 2010, 4:09:35 AM2/7/10
to powe...@googlegroups.com
Hi Johan,

After looking through the documentation, I finally got it to work.

Session realSession = Session.getDefaultInstance(properties, null);
PowerMockito.stub(PowerMockito.method(Session.class, "getDefaultInstance", Properties.class, Authenticator.class))                     .andReturn(realSession);
MimeMessage mockMessage = PowerMockito.mock(MimeMessage.class);
PowerMockito.whenNew(MimeMessage.class).withParameterTypes(Session.class).withArguments(Mockito.isA(Session.class))
         .thenReturn(mockMessage);

I am having a little difficulty in verifying the execution of methods. My code to verify is as folows:

PowerMockito.verifyNew(MimeMessage.class).withArgument(realSession);

The error stack trace is
Caused by: org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at org.powermock.api.mockito.internal.invocationcontrol.MockitoNewInvocationControl.verify(MockitoNewInvocationControl.java:94)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify final/private/equals() or hashCode() method.
Those methods *cannot* be stubbed/verified.

    at org.powermock.api.mockito.internal.invocationcontrol.MockitoNewInvocationControl.verify(MockitoNewInvocationControl.java:94)
    at org.powermock.api.mockito.PowerMockito.verifyNew(PowerMockito.java:230)
    at swEaiEmailTest.testExecute_criticalPath(swEaiEmailTest.java:156)

    at swEaiEmailTest_$$_javassist_0._d2testExecute_criticalPath(swEaiEmailTest_$$_javassist_0.java)
    ... 27 more


On Thu, Feb 4, 2010 at 11:27 PM, Johan Haleby <johan....@gmail.com> wrote:
This means that PowerMock cannot determine the constructor based on the parameters you sent. In these cases (which ought to be quite rare) you need to specify the parameter types as well e.g.
whenNew(MimeMessage.class).withParameterTypes(MyParameterType.class)I .withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);

Johan Haleby

unread,
Feb 8, 2010, 2:17:30 AM2/8/10
to powe...@googlegroups.com
It's perhaps the same problem with verifyNew as with whenNew, you need to specify the parameter types as well otherwise the wrong constructor may be verified in your case.

/Johan

Kartik Kumar

unread,
Feb 8, 2010, 3:24:42 AM2/8/10
to powe...@googlegroups.com
Hi Johan,

I am sorry if I am missing something. I started using Powermock about 3 days so I may be making rudimentary mistakes.

PowerMockito#verifyNew(Class<?> class) returns an object of ConstructorArgumentVerification. The strategy implementation only exposes withArguments(Object, Object...) or withNoArguments(). I have tried to pass realSession as an argument and Mockito matchers such as Mockito.eq(realSesession) and Mockito.isA(Session.class). I get the same error.

Thanks,

Kartik

Johan Haleby

unread,
Feb 8, 2010, 9:13:55 AM2/8/10
to powe...@googlegroups.com
Sorry my mistake. New instance verification of overloaded constructors is not actually implemented yet in the Mockito API. As a work-around, could you try casting the arguments you pass into "withArguments" to the concrete parameter type(s)? 

/Johan

Karthik Kumar

unread,
Feb 8, 2010, 4:46:34 PM2/8/10
to PowerMock
I tried to pass the realSession to "withArguments" in parameter types.
It fails again with the same error.

On Feb 8, 6:13 am, Johan Haleby <johan.hal...@gmail.com> wrote:
> Sorry my mistake. New instance verification of overloaded constructors is
> not actually implemented yet in the Mockito API. As a work-around, could you
> try casting the arguments you pass into "withArguments" to the concrete
> parameter type(s)?
>
> /Johan
>

> On Mon, Feb 8, 2010 at 9:24 AM, Kartik Kumar <krishnan.1...@gmail.com>wrote:
>
> > Hi Johan,
>
> > I am sorry if I am missing something. I started using Powermock about 3
> > days so I may be making rudimentary mistakes.
>
> > PowerMockito#verifyNew(Class<?> class) returns an object of
> > ConstructorArgumentVerification. The strategy implementation only exposes
> > withArguments(Object, Object...) or withNoArguments(). I have tried to pass
> > realSession as an argument and Mockito matchers such as
> > Mockito.eq(realSesession) and Mockito.isA(Session.class). I get the same
> > error.
>
> > Thanks,
>
> > Kartik
>

> > On Sun, Feb 7, 2010 at 11:17 PM, Johan Haleby <johan.hal...@gmail.com>wrote:
>
> >> It's perhaps the same problem with verifyNew as with whenNew, you need to
> >> specify the parameter types as well otherwise the wrong constructor may be
> >> verified in your case.
>
> >> /Johan
>

> >>> On Thu, Feb 4, 2010 at 11:27 PM, Johan Haleby <johan.hal...@gmail.com>wrote:
>
> >>>> This means that PowerMock cannot determine the constructor based on the
> >>>> parameters you sent. In these cases (which ought to be quite rare) you need
> >>>> to specify the parameter types as well e.g.
> >>>>  whenNew(MimeMessage.class).withParameterTypes(MyParameterType.class)I
> >>>> .withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);
>
> >>>> /Johan
>

> >>>> On Fri, Feb 5, 2010 at 1:53 AM, Kartik Kumar <krishnan.1...@gmail.com>wrote:
>
> >>>>> Hi Johan,
>
> >>>>> I tried your suggestion and I am getting an error message that several
> >>>>> matching constructors are found. I am using TestNG and Mockito.
>

> >>>>> *Test Code*


>
> >>>>> // Mock session classes.
>
> >>>>>         MimeMessage message = PowerMockito.mock(MimeMessage.class);
> >>>>>         PowerMockito.whenNew(MimeMessage.class)
> >>>>>                 .withArguments(Mockito.isA(Session.class))
> >>>>>                 .thenReturn(message);
>
> >>>>>        // These lines are not executed.
>
> >>>>>         PowerMockito.doNothing().when(message)
> >>>>>             .setFrom(Mockito.isA(InternetAddress.class));
> >>>>>         PowerMockito.doNothing().when(message).setRecipient(
> >>>>>                 Mockito.eq(Message.RecipientType.TO),
> >>>>>                 Mockito.isA(InternetAddress.class));
>
> >>>>> PowerMockito.doNothing().when(message).setSubject(Mockito.anyString());
> >>>>>         PowerMockito.doNothing().when(message)
> >>>>>                 .setSentDate(Mockito.any(Date.class));
>
> >>>>> PowerMockito.doNothing().when(message).setText(Mockito.anyString());
> >>>>>         PowerMockito.mockStatic(Transport.class);
> >>>>>         PowerMockito.doNothing().when(Transport.class);
>
> >>>>>         // Call class under test.
> >>>>>         swEaiEmail eaiEmail = new swEaiEmail();
> >>>>>         eaiEmail.execute("", Collections.EMPTY_LIST, inputFields);
> >>>>>         Transport.send(message);
>

> >>>>> *Error Log*

> >>>>> Caused by: *org.powermock.reflect.exceptions.TooManyConstructorsFoundException:


> >>>>> Several matching constructors found, please specify the argument parameter
> >>>>> types so that PowerMock can determine which method you're refering to.

> >>>>> *


> >>>>> Matching constructors in class javax.mail.internet.MimeMessage were:
> >>>>> javax.mail.internet.MimeMessage( javax.mail.Folder.class int.class )
> >>>>> javax.mail.internet.MimeMessage( javax.mail.Session.class
> >>>>> java.io.InputStream.class )
>
> >>>>>     at
> >>>>> org.powermock.reflect.internal.WhiteboxImpl.throwExceptionWhenMultipleConstructorMatchesFound(WhiteboxImpl.java:1408)
> >>>>>     at
> >>>>> org.powermock.reflect.internal.WhiteboxImpl.findUniqueConstructorOrThrowException(WhiteboxImpl.java:904)
> >>>>>     at
> >>>>> org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.createNewSubsituteMock(DefaultConstructorExpectationSetup.java:69)
> >>>>>     at
>

> ...
>
> read more »

Johan Haleby

unread,
Feb 9, 2010, 2:23:06 AM2/9/10
to powe...@googlegroups.com
If you like could you provide a small (preferably maven) project that demonstrates the issue so that I can have a look?

/Johan


--

Kartik Kumar

unread,
Feb 9, 2010, 1:57:32 PM2/9/10
to powe...@googlegroups.com
Hi Johan,

I don't have a maven project, but I have a small source and test code that I have written in TestNG + Mockito. How can I send it to you? Last time I tried to send an attachment to the group, you told me not to do that.

Thanks,

Kartik

Johan Haleby

unread,
Feb 9, 2010, 2:38:57 PM2/9/10
to powe...@googlegroups.com
If you could attach it to the google group that would be great. I.e. go to http://groups.google.com/group/powermock and upload the file there.

/Johan

Kartik Kumar

unread,
Feb 9, 2010, 5:30:32 PM2/9/10
to powe...@googlegroups.com
Hi Johan,

I have attached the soure files here http://groups.google.com/group/powermock/web/MimeHelper.zip

To run the test suite, please run MimeHelperSuite

Johan Haleby

unread,
Feb 10, 2010, 2:33:58 AM2/10/10
to powe...@googlegroups.com
Great! I'll look into to it when I get some time.

Johan Haleby

unread,
Feb 10, 2010, 2:48:32 AM2/10/10
to powe...@googlegroups.com
Hi,

The problem was that the verifyNew wasn't followed by the arguments so the verification was not completed and thus the UnfinishedVerificationException was thrown.
So this:
PowerMockito.verifyNew(Properties.class)
Should be:
PowerMockito.verifyNew(Properties.class).withNoArguments();

/Johan

Kartik Kumar

unread,
Feb 15, 2010, 2:07:55 PM2/15/10
to powe...@googlegroups.com
Hi Johan,

Thanks for your help. I applied your suggestion and it worked. But verification of final classes and static initializers are a still a problem for me. This is my method to be tested.

public MimeMessage createMessage(Properties properties) {
        Session session = Session.getDefaultInstance(properties, null);
        return new MimeMessage(session);
 }

This is my test method.
@Test(description = "test powermock mime message creation")
    public void testCreateMessage() throws Exception {
        Session realSession = Session.getDefaultInstance(this.properties, null);
        PowerMockito.mock(Session.class);

        PowerMockito.stub(PowerMockito.method(Session.class,
                "getDefaultInstance", Properties.class, Authenticator.class))
                .andReturn(realSession);
        MimeMessage message = PowerMockito.mock(MimeMessage.class);
        PowerMockito.whenNew(MimeMessage.class).withParameterTypes(Session.class)
                .withArguments(realSession).thenReturn(message);
        MimeHelper helper = new MimeHelper();
        MimeMessage testMessage = helper.createMessage(this.properties);
        Assert.assertNotNull(testMessage);
        PowerMockito.verifyStatic(Mockito.times(2));
        Session.getDefaultInstance(Mockito.isA(Properties.class),
                (Authenticator) Mockito.isNull());
        PowerMockito.verifyNew(MimeMessage.class).withArguments(Mockito.any(Session.class));
    }

For the statement in bold, I have also tried the following options

1. PowerMockito.verifyNew(MimeMessage.class)withArguments(realSession);
2. PowerMockito.verifyNew(MimeMessage.class).withArguments(Mockito.isA(Session.class));

and I get the same error message. The funny thing is that this verification statement causes my other test to fail, the one that you helped me fix. If I remove this statement, my other test passes.


java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.invoke(PowerMockTestNGMethodHandler.java:48)
    at MimeHelperTest_$$_javassist_0.testCreateMessage(MimeHelperTest_$$_javassist_0.java)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:644)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:546)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:700)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1002)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
    at org.testng.TestRunner.runWorkers(TestRunner.java:909)
    at org.testng.TestRunner.privateRun(TestRunner.java:618)
    at org.testng.TestRunner.run(TestRunner.java:499)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:332)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:327)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:299)
    at org.testng.SuiteRunner.run(SuiteRunner.java:204)
    at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:915)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:879)
    at org.testng.TestNG.run(TestNG.java:787)
    at MimeHelperSuite.main(MimeHelperSuite.java:10)

Caused by: org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at org.powermock.api.mockito.PowerMockito.verifyStatic(PowerMockito.java:155)
Reply all
Reply to author
Forward
0 new messages