Как протестировать Сервис с вызовами внешнего API в Spring - PullRequest
0 голосов
/ 24 марта 2020

Хорошо, так что я довольно новичок в тестировании и Spring Boot в целом, поэтому, пожалуйста, исправьте меня, если я делаю что-то совершенно не так, в первую очередь.

Как проект, который я и моя команда делаем веб-приложение, использующее Spring Boot, где мы выполняем вызовы Microsoft Graph API в некоторых наших службах. Смотрите этот сервис для отмены события в календаре пользователя:

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();
    }
}

Это прекрасно работает, но я пару дней боролся с тем, как написать для этого модульные тесты. На мой взгляд, я хочу либо сделать макеты GraphServiceClient, либо использовать такой инструмент, как WireMock, чтобы сделать запрос go на mockserver и вернуть некоторые значения, которые я настраиваю.

Я пытался сделать и то и другое, но я не могу сделать макеты GraphServiceClient, потому что это не Бин в моем проекте, поэтому я не могу понять, как мне следует приступить к созданию реализации, которую я могу автоматически связать в моей службе.

Когда дело доходит до WireMock, я даже не уверен, что понимаю, способен ли он делать то, что я хочу, и если это так, я точно не смог правильно его настроить (обратите внимание, что мы используя JUnit 5 для этого проекта). Простого примера, когда вы делаете GET-запрос к Google.com и возвращаете «Hello» через WireMock, достаточно для того, чтобы я тут оказался.

Любые конкретные примеры того, что я должен сделать, или даже просто кивок правильное направление будет хорошо оценено.

Ответы [ 2 ]

1 голос
/ 25 марта 2020

В продолжение этого мы нашли решение проблемы, создав класс GraphServiceClientImpl с методом, который возвращает экземпляр класса 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();
    }
}

Затем наш тест:

@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();
    }
}

Возможно, не оптимальное решение, но оно работает. Любые другие варианты этого приветствуются!

1 голос
/ 24 марта 2020

Ну, я не могу заверить вас, что это будет работать, но это даст вам лучший обзор ситуации:

1) Итак, сначала нам нужно внести небольшие изменения в ваш сервис. Необходимо извлечь IGraphServiceClient из метода, чтобы мы могли смоделировать его позже, см .:

@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) Тест будет выглядеть следующим образом: (Обратите внимание, что все, что мы здесь используем, включено в модуль весенней загрузки, поэтому вам не нужно ничего добавлять к зависимостям проекта)

@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();
  }
}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...