【问题标题】:Spring Cloud Eureka - How to mock RestTemplate in order to avoid request to a second serviceSpring Cloud Eureka - 如何模拟 RestTemplate 以避免请求第二个服务
【发布时间】:2020-04-25 13:58:24
【问题描述】:

我正在尝试为我的一个微服务编写一个集成测试,在将对象保存在数据库中之前,调用另一个微服务以执行一些验证。

由于第二个微服务没有运行,我想模拟对外部服务的请求,但测试失败并出现错误:

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)

下面是测试逻辑:

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

任何建议将不胜感激。谢谢!

【问题讨论】:

  • 您的测试是否创建了模拟休息模板 bean?

标签: java microservices spring-cloud spring-cloud-netflix


【解决方案1】:

正如@spencergibb 正确建议的那样,您可以模拟您的 restTemplate 作为测试配置的一部分。

第二个选项,你可以尝试使用 MockRestServiceServer。

检查下面的链接。看看它是否对您有帮助。

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

【讨论】:

    【解决方案2】:

    为了执行我的测试,我执行了以下步骤:

    1.禁用eureka客户端

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

    1.禁用eureka客户端 按照@spancergibb 的建议模拟 RestTemplate 并使用 Autowire 注入我的服务(作为常规 spring bean)

        @Mock
        RestTemplate restTemplateMock
    
        @Autowired
        @InjectMocks
        private PropertyListingService listingService
    
    1. 在模拟 RestTemplate 方法之前调用了 MockitoAnnotations.initMocks(this)。

      MockitoAnnotations.initMocks(这个) URI uri = URI.create(servicesConfig.getUsersServiceURI() + "/rest/users/exists/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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-11
      • 2015-02-12
      • 2020-06-24
      • 1970-01-01
      • 2018-04-15
      • 2018-04-29
      • 2017-07-07
      • 1970-01-01
      • 2019-12-26
      相关资源
      最近更新 更多