Search code examples
javajunitmockitopowermockpowermockito

"Mock" method with fixed parameters


I have a "Mailer" class in my project (which of course sends emails). For testing I want that every call of Mailer#send(String toAddress) is replaced with Mailer#send("[email protected]").

So something like:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassCallingMailer.class})
public class TestClass {

    @Test
    public void testMethod() {
        Mailer mailerMock = mock(Mailer.class);
        // this is where the magic happens; replace any toAddress with fixed email address
        when(mailerMock.send(any(String.class))).thenReturn(mailerMock.send("[email protected]"));
        try {
            whenNew(Mailer.class).withAnyArguments().thenReturn(mailerMock);
        } catch (Exception e) {
            e.printStackTrace();
        }

        ClassCallingMailer someClass = new ClassCallingMailer();
        assertTrue(someClass.methodSendingMail());
    }
}

This code obviously is not working, but can this be achieved in some way? Maybe this is a completely wrong approach?

Thank you.


UPDATE

I'm not really sure how good this is but it's working:

// ClassCallingMailer (no changes, just for completeness)
public class ClassCallingMailer {
    public boolean methodSendingMail() {
        Mailer mail = new Mailer();
        return mail.send(someEmailAddress);
    }
}

// TestMailer (new class)
public class TestMailer extends Mailer {
    // add all constructors from Mailer
    @Override
    public boolean send(String to) {
        return super.send("[email protected]");
    }
}

// TestClass (with changes)
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassCallingMailer.class})
public class TestClass {

    @Test
    public void testMethod() {
        // changed mock to spy and replaced Mailer with TestMailer
        Mailer mailerMock = spy(TestMailer.class);
        // removed "when(...).thenReturn(...)"
        try {
            whenNew(Mailer.class).withAnyArguments().thenReturn(mailerMock);
        } catch (Exception e) {
            e.printStackTrace();
        }

        ClassCallingMailer someClass = new ClassCallingMailer();
        assertTrue(someClass.methodSendingMail());
    }
}

Solution

  • If you want to achieve only this behavior, I would suggest not to do by mocking. You can extend your Mailer class to have some TestMailer in which you can do something like:

    @Override
    public void send(String toAddress){
      super.send("[email protected]");
    }
    

    Basically you override the original send from the Mailer and call it with the predefined address.

    You can use this new subclass in your tests.