dest
dest

Reputation: 79

How to test a call to external api in Spring Boot

I have a method in the service class that uses an external wrapper to call the slack api. The wrapper I'm using is this one if it makes any difference. This is how I'm using the wrapper,

//This is the method in my service class
public String sendMess(SlackObj obj) {
    //SlackObj contains the channel url, channel name and the message
    //build the payload from the SlackObj
    //Slack is the name of the wrapper's class that I'm using
    Slack slack = Slack.getInstance();
    //slack.send is the method that sends the message to slack
    WebhookResponse res = slack.send(url, payload);
    //other logic
}

//This is what I've tried
@Test
public void slackSendMessageTest(){
    //build the slack obj and payload
    //build the mock WebhookResponse
    Slack slackMock = mock(Slack.class)
    when(slackMock.send(channelUrl, payload)).thenReturn(mockWebHookRes);
    assertEquals("SUCCESS", testService.sendMessage(testSlackObj);
}

I am trying to write some tests for this method, so my question is, how would i test it without having the message sent every time I run the test? I believe the cause of this is because slack itself is not mocked and I have no idea as how to inject the mock into the mocked service class.

I am open to refactoring the service class if it helps with the testing. Any suggestions and recommendation is appreciated. Thanks.

Upvotes: 0

Views: 2818

Answers (1)

Todd
Todd

Reputation: 31720

You are going to have to find a way to mock Slack, which appears to be a singleton, unfortunately.

Here's what I would do:

1) Make Slack available as a bean that can be autowired:

@Configuration
public class SlackConfiguration {

    @Bean
    public Slack slack() {
        return Slack.getInstance();
    }
}

2) Change your class to take an injected Slack:

Note that I am totally guessing on the name here, as you just show the method. You would inject the Slack object you turned into a @Bean above, and not use Slack.getInstance() directly anywhere else.

@Component
public class SlackService {
    private final Slack slack;

    @Autowired
    public SlackService(final Slack slack) {
        this.slack = slack;
    }

    public String sendMessage(final Object message) {
        final WebhookResponse res = slack.send(url, payload);
        // etc
    }
}

3) Mock the Slack object and pass it to your SlackService in test:

This allows you to mock out the implementation of Slack, so you can alter its behavior. I won't go into mocking in detail.

public class SlacServiceTest {
    private final Slack slack = mock(Slack.class);
    private final SlackService serviceUnderTest = new SlackService(slack);

    @Test
    public void testSomething() {
        // TODO: set mock responses here
        // Given... when... then...
    }

}

Upvotes: 5

Related Questions