Reputation: 51
Okay, so I am pretty new to testing and Spring Boot in general, so please correct me if I am doing something completely wrong here in the first place.
As a project my team and I are making a Web Application using Spring Boot where we are making calls to the Microsoft Graph API in some of our services. See this service for cancelling an event in a user's calendar:
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.models.extensions.IGraphServiceClient;
import com.microsoft.graph.requests.extensions.GraphServiceClient;
import org.springframework.stereotype.Service;
@Service
public class CancelEventService {
public void cancelEvent(final String token, final String id) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
IGraphServiceClient graphServiceClient = GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
graphServiceClient.me().events(id)
.buildRequest()
.delete();
}
}
This is working great, but I have been struggling for a couple of days with how to write unit tests for this. The way I see it, I want to either make mocks of the GraphServiceClient, or use a tool like WireMock to make the request go to a mockserver and return some values I configure.
I've tried doing both, but I can't make mocks of GraphServiceClient because it is not a Bean in my project, so I can't figure out how I should proceed to make an implementation I can autowire in to my Service.
When it comes to WireMock I am not even sure I understand if it is capable of doing what I want to, and if it is, I sure haven't been able to configure it correctly (note that we are using JUnit 5 for this project). A simple example where you make a GET-request to Google.com and return "Hello" via WireMock would suffice to get me going here.
Any concrete examples of what I should do, or even just a nod in the right direction would be well appreciated.
Upvotes: 3
Views: 2985
Reputation: 51
As a follow up on this, we found a solution to the problem by creating a class GraphServiceClientImpl with a method that returns an instantiated GraphServiceClient.
@Component
public class GraphServiceClientImpl {
public IGraphServiceClient instantiateGraphServiceClient(final String token) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
return GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
}
}
@Service
public class CancelEventService{
private GraphServiceClientImpl graphServiceClientImpl;
public CancelEventService(final GraphServiceClientImpl graphServiceClientImpl) {
this.graphServiceClientImpl = graphServiceClientImpl;
}
public void cancelEvent(final String token, final String id) {
IGraphServiceClient graphServiceClient = graphServiceClientImpl.instantiateGraphServiceClient(token);
graphServiceClient
.me()
.events(id)
.buildRequest()
.delete();
}
}
Then, our test:
@ExtendWith(MockitoExtension.class)
class CancelEventServiceTest {
@Mock
private GraphServiceClientImpl graphServiceClientImpl;
@InjectMocks
private CancelEventService cancelEventService;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
void cancelEvent_Successful() {
//given
IGraphServiceClient serviceClientMock = mock(IGraphServiceClient.class, RETURNS_DEEP_STUBS);
given(graphServiceClientImpl.instantiateGraphServiceClient(anyString())).willReturn(serviceClientMock);
//when
cancelEventService.cancelBooking("Token", "1");
//then
verify(serviceClientMock, times(1)).me();
}
}
Probably not the optimal solution, but it works. Any other takes on this would be welcome!
Upvotes: 2
Reputation: 76
Well, I cannot assure you that it will work but it will give you a better landscape of the situation:
1) So first, we need to make a slight change on your service. Need to extract IGraphServiceClient from the method so we can mock it later, see:
@Service
public class CancelEventService {
private IGraphServiceClient graphServiceClient;
@Autowired
public CancelEventService(IGraphServiceClient graphServiceClient){
this.graphServiceClient = graphServiceClient;
}
public void cancelEvent(final String token, final String id) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
graphServiceClient = GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
graphServiceClient.me().events(id)
.buildRequest()
.delete();
}
}
2) The test would look like this: (Notice that all we are using here is included in spring boot test module, so you shouldn't need to add anything to the project dependencies)
@RunWith(SpringRunner.class)
public class CancelEventServiceTest {
private IGraphServiceClient graphServiceClientMock;
private CancelEventService serviceToBeTested;
@Before
public void setUp(){
graphServiceClientMock = Mockito.mock(IGraphServiceClient.class, RETURNS_DEEP_STUBS);
serviceToBeTested = new CancelEventService(graphServiceClientMock);
}
@Test
public void test_1() {
serviceToBeTested.cancelEvent("token", "id");
verify(graphServiceClientMock, times(1)).me().events("id").buildRequest()
.delete();
}
}
Hope it helps!
Upvotes: 4