Spring Cloud Eureka - Как смоделировать RestTemplate, чтобы избежать запроса ко второму сервису - PullRequest
0 голосов
/ 08 января 2020

Я пытаюсь написать интеграционный тест для одного из моих микросервисов, который перед сохранением объекта в базе данных вызывает другой микросервис для выполнения некоторой проверки.

Поскольку второй микросервис не выполняется, я хочу смоделировать запрос к внешней службе, но тест не выполняется с ошибкой:

Condition failed with Exception:

mockServer.verify()
|          |
|          java.lang.AssertionError: Further request(s) expected leaving 1 unsatisfied expectation(s).
|          0 request(s) executed.
|           
|           at org.springframework.test.web.client.AbstractRequestExpectationManager.verify(AbstractRequestExpectationManager.java:159)
|           at org.springframework.test.web.client.MockRestServiceServer.verify(MockRestServiceServer.java:116)

Ниже приведен лог теста c:

@SpringBootTest(classes = PropertyApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        properties = ["eureka.client.enabled:false"])
class TestPropertyListingServiceDemo extends IntegrationTestsSetup {
@Autowired
private PropertyListingService listingService
@Autowired
private RestTemplate restTemplate

private static MockRestServiceServer mockServer


def setup() {
    mockServer = MockRestServiceServer.createServer(restTemplate)
}


def "test: save listing for in-existent User"() {

    setup: "building listing with invalid user id"
    def listing = generatePropertyListing()

    mockServer.expect(once(), requestTo("http://user-service/rest/users/exists/trackingId=" + listing.getUserTID()))
            .andExpect(method(GET))
            .andRespond(withStatus(NOT_FOUND).body("No such user."))


    when: "saving listing"
    listingService.save(listing)

    then: "exception is thrown"
    mockServer.verify() // <------------- here I am getting the error

    BizItemBusinessValidationException e = thrown()
    e.getMessage() == "Listing could not be saved. User not found."
}

}

Служба, которую я тестирую с запросом, который я пытаюсь смоделировать:

@Service
public class PropertyListingService {
private BizItemService itemService;
private PropertyService propertyService;
private RestTemplate restTemplate;

public PropertyListingService(BizItemService itemService,PropertyService propertyService, RestTemplate restTemplate) {
    this.propertyService = propertyService;
    this.restTemplate = restTemplate;
    this.itemService=itemService;
}


public PropertyListing save(PropertyListing listing) {

    if (listing == null) {
        throw new BizItemBusinessValidationException("Listing could not be saved. Invalid Listing.");
    }

    if (propertyService.findByTrackingId(listing.getPropertyTID()) == null) {
        throw new BizItemBusinessValidationException("Listing could not be saved. Property not found.");
    }

    if (userExists(listing.getUserTID())) {
        throw new BizItemBusinessValidationException("Listing Could not be saved. User not found, UserTID = " + listing.getUserTID());
    }

    return (PropertyListing) itemService.save(listing);
}


/**------------------------------------------------------------
 * THIS IS THE CALL TO EXTERNAL SERVICE I AM TRYING TO MOCK
 * ------------------------------------------------------------
 */

private boolean userExists(String userTID) {
    URI uri = URI.create("http://user-service/rest/users/exists/trackingId=" + userTID);
    ResponseEntity response = (ResponseEntity) restTemplate.getForObject(uri, Object.class);

    return response != null && response.getStatusCode() == HttpStatus.OK;
}

}

Конфигурация RestTemplate:

@Configuration
public class BeanConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

Любое предложение будет высоко ценится Спасибо!

Ответы [ 2 ]

1 голос
/ 08 января 2020

Как правильно заметил @spencergibb, вы можете смоделировать ваш restTemplate как часть ваших тестовых конфигураций.

Второй вариант, вы можете попробовать использовать MockRestServiceServer.

Проверьте ссылку ниже. Посмотрите, поможет ли это вашему делу.

https://www.baeldung.com/spring-mock-rest-template

0 голосов
/ 08 января 2020

Чтобы выполнить мои тесты, я сделал следующие шаги:

1. Отключенный клиент eureka

@SpringBootTest(classes = PropertyApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["eureka.client.enabled:false"])

1. Отключенный клиент eureka Mocked RestTemplate, предложенный @spancergibb, и ввел мою службу с помощью Autowire (как обычная пружинная фасоль)

    @Mock
    RestTemplate restTemplateMock

    @Autowired
    @InjectMocks
    private PropertyListingService listingService

Вызывал MockitoAnnotations.initMocks (this) перед тем, как имитировать метод RestTemplate.

MockitoAnnotations.initMocks (this) URI uri = URI.create (servicesConfig.getUsersServiceURI () + "/ rest / users / exist / trackingId =" + userTID)

Mockito.when (restTemplateMock.getForEntity (uri, ResponseEntity.class)). ThenReturn (responseEntity)

Ниже приведен мой полный тестовый класс:

@SpringBootTest(classes = PropertyApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["eureka.client.enabled:false"])
class TestPropertyListingService extends IntegrationTestsSetup {


    @Mock
    RestTemplate restTemplateMock

    @Autowired
    @InjectMocks
    private PropertyListingService listingService

    @Autowired
    private PropertyService propertyService

    static boolean testsSetupExecuted
    static Property dbProperty

    def setup() {
        if (!testsSetupExecuted) {
            schemaService.initSchema()
            purgeCollection(PropertyListing.simpleName)
            dbProperty = propertyService.save(generateProperty())
            testsSetupExecuted = true
        }
    }


    def "test: save listing for in-existent User"() {
        setup:
        def listing = generatePropertyListing()
        listing.setPropertyTID(dbProperty.getTrackingId())
        mockUserRestCall(listing.userTID, new ResponseEntity("Mocking: User not found", NOT_FOUND))

        when: "saving listing"
        listingService.save(listing)

        then: "exception is thrown"
        BizItemBusinessValidationException e = thrown()
        e.getMessage() == "Listing could not be saved. User not found, UserTID = ${listing.userTID}"
    }

    def "test: save listing with past checkin/checkout date"() {
        setup:
        def listing = generatePropertyListing()
        listing.setPropertyTID(dbProperty.getTrackingId())
        mockUserRestCall(listing.userTID, new ResponseEntity("Mocked response", OK));

        when: "saving with past dates"
        listing.setCheckInDate(new Date(System.currentTimeMillis() - 100000))
        listing.setCheckOutDate(new Date(System.currentTimeMillis() - 100000))
        listingService.save(listing)

        then: "exception is thrown"
        BizItemSchemaValidationException e = thrown()
        e.getMessage().startsWith('[PropertyListing] validation failed [[Invalid future date for [CheckIn Date] =')
        e.getMessage().contains('Invalid future date for [CheckOut Date] =')
    }



    def mockUserRestCall(String userTID, ResponseEntity responseEntity) {
        MockitoAnnotations.initMocks(this)
        URI uri = URI.create(servicesConfig.getUsersServiceURI() + "/rest/users/exists/trackingId=" + userTID)
        Mockito.when(restTemplateMock.getForEntity(uri, ResponseEntity.class)).thenReturn(responseEntity)
    }
}
...