简体   繁体   中英

how to mock a class used in the code

public void sendMail() {  
    /* I have simplified the method for here */
    Transport t;
    t.send();
}

When I am writing unit test for this, since I don't want to actually send the mail, I want to mock the Transport class. Is it possible and if so, how to do it ?

'cglib' may fits.
Use 'Enhancer' to proxy the 'Transport' class. In order not to actually sending the mail, you need pass into the 'Enhancer' a 'MethodInterceptor' which will not invoke the 'send()' method in super class.

Unless you really want to use mockito, you can quite easily handcraft your own test double.

What you can do is create an interface that knows how to send mail:

public interface TransportInterface {
    public void send(Message msg);
}

Let the mail sending class use this interface to send the mail:

public class MailSender {
    private TransportInterface transport;

    public MailSender(TransportInterface transport) {
        this.transport = transport;
    }

    public void sendMail(Message msg) {
        /* This is the method from your question */
        this.transport.send(msg);
    }
}

In production you use an implemenation of TransportInterface that actually send the mail:

public class TransportAdapter implements TransportInterface {
    private Transport transport; // Created elsewhere...

    public void sendMail(Message msg) {
        transport.send(msg);
    }
}

And in your test code you can use a fake:

public class TransportFake implements TransportInterface {
    public void sendMail(Message msg) {
        // I don't send the mail!
    }
}

(It's been a while since I coded java. Hope there are not too many errors. Also, you can probably do a better job naming the classes than I have.)

You can try to use Mockito library: here is example code:

import org.mockito.Mock;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class YourTestClass{
@Mock
Transport t;

@Test
public void someTest(){
t = Mockito.mock(Transport .class);
    Mockito.when(t.send()).thenReturn(true);
}
}

Here is a solution which works regardless of how the Transport t object is obtained:

@Test
public sendMail(
    // Mocks all current and future Transport instances, 
    // including those belonging to subclasses (if any).
    @Capturing final Transport t)
{
    new SUT().sendMail();

    // Verifies that the t.send() method was called:
    new Verifications() {{ t.send(); }};
}

The mocking API used above is JMockit (which I develop).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM