文章目录

  • 集成测试
  • @SpringBootTest的集成测试
  • Spring Boot Test集成测试环境搭建
  • 参考
  • 源代码

集成测试

集成测试(Integration Testing,缩写为INT)将多个模块结合在一起进行测试,确保多个组件可以正确交互。当它失败表示你的各个代码块间无法有效协作。

集成测试可以是下面其中一项:

  • 测试两个或多个类之间的交互。
  • 包含多层的测试。包括业务服务和持久层之间的交互。
  • 包含整个应用程序整个路径的测试。在这些测试中,我们向应用程序发送一个请求,并检查它是否正确响应并根据我们的期望更改了数据库状态。

@SpringBootTest的集成测试

Spring Boot提供了@SpringBootTest注释,可用于创建一个的application context上下文,这个application context中的对象(比如server层,dao层的对象)都是被Spring真实管理的,并不是通过mock方式虚拟出来的。但是请注意,过度使用@SpringBootTest 可能会导致测试的运行时间很长。

事实上,我们应该用更多的单元测试去覆盖我们的代码,因为在自动化测试的金字塔中,单元测试的占比应该是最大的,在单元测试中,我们可以手动创建需要测试的对象,然后通过Stub和Mock来模拟这些外部依赖的对象。比如测试Controller层的时候,我们可以把service层Mock掉,测试service层的时候我们可以把dao层Mock掉。尽可能多的单元测试来代替集成测试,因为使用集成测试需要Spring在每次启动测试时都启动整个应用程序上下文,会导致自动化测试的运行时间过长。而且一旦应用程序变大,Spring需要花更多的时间,因为Spring必须将越来越多的bean加载到应用程序上下文中。

我个人认为应该把每个测试的方法拆分的更加细,不是简单从请求到DB的流程,而是应该专注你需要测试的业务逻辑,可以把依赖的接口或者不是你关注重点的依赖数据都可以Mock和Stub掉。用更多的单元测试去覆盖,这样一方面可以减少自动化测试的运行时间,因为不需要启动整个应用程序上下文,而且更加能保证代码的质量。

当然,对于需要覆盖从传入请求到数据库的整个Spring Boot应用程序的测试,或者需要测试到与数据库交互或者业务服务和持久层之间交互的,我们可以并且应该使用@SpringBootTest。

Spring Boot Test集成测试环境搭建

  1. 首先我这里提取了一个专门测试用的module,用来放跟测试有关的common类,还有管理测试相关的依赖包

  2. 我们加入测试需要的依赖。

       <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId></dependency><dependency><groupId>com.github.javafaker</groupId><artifactId>javafaker</artifactId></dependency><dependency><groupId>com.cc.cloud</groupId><artifactId>cloud-common</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>provided</scope></dependency>

并在parent pom文件中管理依赖的版本。

            <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>2.4.0</version></dependency><dependency><groupId>com.github.javafaker</groupId><artifactId>javafaker</artifactId><version>1.0.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.7</version></dependency>

下面介绍一下上面的一些依赖的作用。

  • json-path 是json解析工具,当我们测试controller层的时候,可以很方便的解析并测试我们返回的json数据。
  • javafaker是测试造数据的神器,可以帮我们生成姓名,地址之类的测试数据。
  • cloud-common 这个是我抽取的一些common需要用到的类或者依赖。
  • spring-tx和jackson-databind和spring-boot-starter-web是我们一会抽取测试基类的时候会用到的依赖。
  1. 抽取测试基类
package com.cc.cloud.test.common;import com.github.javafaker.Faker;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;@RunWith(SpringRunner.class)
@ActiveProfiles({"test"})
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)//目录层次结构与主类一致,classes属性可以不指定启动类
@FixMethodOrder(MethodSorters.NAME_ASCENDING) //JUnit中按照字母顺序执行测试
@Transactional //@Transactional 注释标签是表明此测试类的事务启用,这样所有的测试方案都会自动的rollback,即不用自己清除自己所做的任何对数据库的变更了
@Ignore
public abstract class IntegrationTestBase {private Faker faker;public Faker getFaker() {return this.faker;}@Beforepublic void initIntegrationTestBase() {this.faker = new Faker();}
}

这里抽取了一个测试的基类IntegrationTestBase,用于所有的集成测试的基类。

然后下面有抽取了一个测试的基类,继承了IntegrationTestBase。用于所有Controller层测试的基类。

package com.cc.cloud.test.common;import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Ignore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;@Ignore
public abstract class ControllerTestBase extends IntegrationTestBase {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;private ObjectMapper jsonMapper;@Beforepublic void initControllerTestBase() {this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();this.jsonMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);}public MockMvc getMockMvc() {return this.mockMvc;}public ObjectMapper getJsonMapper() {return this.jsonMapper;}
}
  1. Spring Boot Test集成测试的配置。

我们创建一个bootstrap-test.yml文件,首先为什么是这个命名呢,因为我们前面指定了@ActiveProfiles({"test"}),所以我们profiles指定了test,所以后缀需要加上test。但是为什么不是application-test.yml文件呢?因为我试过在application-test.yml配置,但是发现测试运行是报错的。

21:24:06.698 [main] DEBUG org.springframework.test.context.junit4.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class com.cc.cloud.member.controller.MemberControllerTest]
21:24:06.719 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
21:24:06.760 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
21:24:06.858 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.cc.cloud.member.controller.MemberControllerTest] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
21:24:06.907 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.cc.cloud.member.controller.MemberControllerTest], using SpringBootContextLoader
21:24:06.916 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.cc.cloud.member.controller.MemberControllerTest]: class path resource [com/cc/cloud/member/controller/MemberControllerTest-context.xml] does not exist
21:24:06.919 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.cc.cloud.member.controller.MemberControllerTest]: class path resource [com/cc/cloud/member/controller/MemberControllerTestContext.groovy] does not exist
21:24:06.919 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.cc.cloud.member.controller.MemberControllerTest]: no resource found for suffixes {-context.xml, Context.groovy}.
21:24:06.922 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.cc.cloud.member.controller.MemberControllerTest]: MemberControllerTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
21:24:07.471 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [C:\Users\c\Desktop\spring-cloud-demo\cloud-service-member\target\classes\com\cc\cloud\member\MemberApp.class]
21:24:07.473 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.cc.cloud.member.MemberApp for test class com.cc.cloud.member.controller.MemberControllerTest
21:24:08.010 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.cc.cloud.member.controller.MemberControllerTest]: using defaults.
21:24:08.011 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
21:24:08.116 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@57d7f8ca, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@76c3e77a, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@78123e82, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@67c33749, org.springframework.test.context.support.DirtiesContextTestExecutionListener@fba92d3, org.springframework.test.context.transaction.TransactionalTestExecutionListener@662b4c69, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@fa49800, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@71238fc2, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@2a54a73f, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@16a0ee18, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@3d6f0054, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@505fc5a4]
21:24:08.121 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.122 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.cc.cloud.member.controller.MemberControllerTest]21:24:08.142 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.142 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.cc.cloud.member.controller.MemberControllerTest]21:24:08.151 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.151 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.153 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.153 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.214 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@21e360a testClass = MemberControllerTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@5ba3f27a testClass = MemberControllerTest, locations = '{}', classes = '{class com.cc.cloud.member.MemberApp}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@226a82c4, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@6b53e23f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@15bb6bea, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@45f45fa1], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false]], class annotated with @DirtiesContext [false] with mode [null].
21:24:08.215 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved @ProfileValueSourceConfiguration [null] for test class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.215 [main] DEBUG org.springframework.test.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.cc.cloud.member.controller.MemberControllerTest]
21:24:08.276 [main] DEBUG org.springframework.test.context.support.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext@21e360a testClass = MemberControllerTest, testInstance = com.cc.cloud.member.controller.MemberControllerTest@434a63ab, testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@5ba3f27a testClass = MemberControllerTest, locations = '{}', classes = '{class com.cc.cloud.member.MemberApp}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@226a82c4, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@6b53e23f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@15bb6bea, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@45f45fa1], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false]]].
21:24:08.335 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}
2019-11-07 21:24:14.632  INFO [cloud-service-member,,,] 1552 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.retry.annotation.RetryConfiguration' of type [org.springframework.retry.annotation.RetryConfiguration$$EnhancerBySpringCGLIB$$e4319f5] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-11-07 21:24:14.666  INFO [cloud-service-member,,,] 1552 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$349984cd] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-11-07 21:24:19.171  INFO [cloud-service-member,,,] 1552 --- [           main] o.s.cloud.commons.util.InetUtils         : Cannot determine local hostname
2019-11-07 21:24:19.195  INFO [cloud-service-member,,,] 1552 --- [           main] o.s.c.n.eureka.InstanceInfoFactory       : Setting initial instance status as: STARTING
2019-11-07 21:24:19.297  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Initializing Eureka in region us-east-1
2019-11-07 21:24:21.815  INFO [cloud-service-member,,,] 1552 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON encoding codec LegacyJacksonJson
2019-11-07 21:24:21.816  INFO [cloud-service-member,,,] 1552 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON decoding codec LegacyJacksonJson
2019-11-07 21:24:22.035  INFO [cloud-service-member,,,] 1552 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using XML encoding codec XStreamXml
2019-11-07 21:24:22.035  INFO [cloud-service-member,,,] 1552 --- [           main] c.n.d.provider.DiscoveryJerseyProvider   : Using XML decoding codec XStreamXml
2019-11-07 21:24:22.562  INFO [cloud-service-member,,,] 1552 --- [           main] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration
2019-11-07 21:24:24.749  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Disable delta property : false
2019-11-07 21:24:24.749  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Single vip registry refresh property : null
2019-11-07 21:24:24.749  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Force full registry fetch : false
2019-11-07 21:24:24.749  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Application is null : false
2019-11-07 21:24:24.750  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Registered Applications size is zero : true
2019-11-07 21:24:24.750  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Application version is -1: true
2019-11-07 21:24:24.750  INFO [cloud-service-member,,,] 1552 --- [           main] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2019-11-07 21:24:28.885 ERROR [cloud-service-member,,,] 1552 --- [           main] c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8888/eureka/}com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connectat com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1]at com.sun.jersey.api.client.filter.GZIPContentEncodingFilter.handle(GZIPContentEncodingFilter.java:123) ~[jersey-client-1.19.1.jar:1.19.1]at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.9.8.jar:1.9.8]at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar:1.19.1]at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar:1.19.1]at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar:1.19.1]at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509) ~[jersey-client-1.19.1.jar:1.19.1]at com.netflix.discovery.shared.transport.jersey.AbstractJerseyEurekaHttpClient.getApplicationsInternal(AbstractJerseyEurekaHttpClient.java:194) ~[eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.jersey.AbstractJerseyEurekaHttpClient.getApplications(AbstractJerseyEurekaHttpClient.java:165) ~[eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$6.execute(EurekaHttpClientDecorator.java:137) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.MetricsCollectingEurekaHttpClient.execute(MetricsCollectingEurekaHttpClient.java:73) ~[eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$6.execute(EurekaHttpClientDecorator.java:137) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.executeOnNewServer(RedirectingEurekaHttpClient.java:118) ~[eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.execute(RedirectingEurekaHttpClient.java:79) ~[eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$6.execute(EurekaHttpClientDecorator.java:137) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:120) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$6.execute(EurekaHttpClientDecorator.java:137) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.DiscoveryClient.getAndStoreFullRegistry(DiscoveryClient.java:1051) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.DiscoveryClient.fetchRegistry(DiscoveryClient.java:965) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:414) [eureka-client-1.9.8.jar:1.9.8]at com.netflix.discovery.DiscoveryClient.<init>(DiscoveryClient.java:269) [eureka-client-1.9.8.jar:1.9.8]at org.springframework.cloud.netflix.eureka.CloudEurekaClient.<init>(CloudEurekaClient.java:63) [spring-cloud-netflix-eureka-client-2.1.0.RC2.jar:2.1.0.RC2]at org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$EurekaClientConfiguration.eurekaClient(EurekaClientAutoConfiguration.java:249) [spring-cloud-netflix-eureka-client-2.1.0.RC2.jar:2.1.0.RC2]at org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$EurekaClientConfiguration$$EnhancerBySpringCGLIB$$983fd3cd.CGLIB$eurekaClient$2(<generated>) [spring-cloud-netflix-eureka-client-2.1.0.RC2.jar:2.1.0.RC2]at org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$EurekaClientConfiguration$$EnhancerBySpringCGLIB$$983fd3cd$$FastClassBySpringCGLIB$$593f1583.invoke(<generated>) [spring-cloud-netflix-eureka-client-2.1.0.RC2.jar:2.1.0.RC2]at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) [spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]

这是为什么呢?因为我们测试的这个微服务中配置了spring config client,并且我们已经把我们的配置抽取到了远程的配置中心了。所以当启动测试服务的时候,会先读取bootstrap.yml,然后连接eureka服务,找到config server,然后config client请求config server去读取远程的配置。 但是由于我们的eureka和config server在测试环境下都是没有启动的,自然就会出现连接错误的问题。

这种时候我们需要怎么解决呢?我的解决方法如下:

因为当我们设置了profiles为test的时候,其实会先读取bootstrap.yml然后再读取bootstrap-test.yml,而且后面的配置会覆盖前面的配置。最后结合这两个配置去启动服务。所以我们可以在bootstrap-test.yml去设置关闭我们的eureka还有config client。

下面给我的配置:

spring:datasource:druid:# jdbc:h2:mem:指定databaseName; 内存模式# DB_CLOSE_DELAY=-1 关闭连接后数据库将被清空,适合测试环境# MODE=MYSQL 兼容模式为MYSQL# DB_CLOSE_ON_EXIT=FALSE    VM存在时不关闭数据库url: jdbc:h2:mem:member_service_db;MODE=MYSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSEusername: sapassword: sadriver-class-name: org.h2.Driverplatform: h2# schema: classpath:schema.sql //程序运行时,使用schema.sql来创建数据库中的表data: classpath:/db/init-data.sql # 程序运行时,使用data.sql来创建初始数据jpa:database-platform: org.hibernate.dialect.MySQL5InnoDBDialectdatabase: h2show-sql: truehibernate:ddl-auto: create-drop # 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。properties:hibernate:show_sql: true # 操作数据库时显示sql语句use_sql_comments: true # SQL 语句中输出便于调试的注释信息format_sql: truedialect: org.hibernate.dialect.MySQL5InnoDBDialectjdbc:time_zone: UTCh2: # 开启h2的控制台console:enabled: truepath: /consolesettings:trace: falseweb-allow-others: truecloud:bus:enabled: false # 关闭Spring Cloud Bus,关闭连接RabbitMQconfig:enabled: false # disable configdiscovery:enabled: false # disable configdiscovery: # disable eurekaenabled: false
eureka:client:enabled: false # disable eureka
  1. Controller测试
package com.cc.cloud.member.controller;import com.cc.cloud.member.domain.Member;
import com.cc.cloud.test.common.ControllerTestBase;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;public class MemberControllerTest extends ControllerTestBase {@Testpublic void findAllMembers() throws Exception {this.getMockMvc().perform(get("/member").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andDo(MockMvcResultHandlers.print()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$.code").value(1)).andExpect(jsonPath("$.message").value("成功"));}@Testpublic void addMember() throws Exception {String name = getFaker().name().fullName();Member member = new Member();member.setMemberName(name);this.getMockMvc().perform(post("/member").content(getJsonMapper().writeValueAsString(member)).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()).andDo(MockMvcResultHandlers.print())//输出整个响应结果信息.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$.code").value(1)).andExpect(jsonPath("$.message").value("成功")).andExpect(jsonPath("$.result.memberName").value(name));}
}
  1. service层测试
package com.cc.cloud.member.service.impl;import com.cc.cloud.member.domain.Member;
import com.cc.cloud.member.service.MemberService;
import com.cc.cloud.test.common.IntegrationTestBase;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;public class MemberServiceImplTest extends IntegrationTestBase {@Autowiredprivate MemberService memberService;@Testpublic void testAddMember() {String name = getFaker().name().fullName();Member member = new Member();member.setMemberName(name);Member addMember = memberService.addMember(member);Assert.assertEquals(name, addMember.getMemberName());}@Testpublic void testFindAllMembers() {Assert.assertEquals(1, memberService.findAllMembers().size());}
}

具体的配置和代码我这里就不多解释了,有些也加了注释,有兴趣的可以参考下面的参考资料。

参考

自动化测试最佳实践(一):从纺锤模型到金字塔模型

Integration Tests with @SpringBootTest

Testing Spring MVC Web Controllers with @WebMvcTest

Spring中文文档翻译Integration Testing(1)

springboot Junit单元测试之坑–@SpringBootTest注解无法加载src/main/resources目录下资源文件

Spring整合Junit4进行单元测试

SpringBoot 优雅的进行单元测试

SpringBoot2.X (十四): @SpringBootTest单元测试

SpringBoot整合Spring Data JPA、MySQL、Druid并使用Mockito实现单元测试

使用H2Database+Druid连接池+Spring Data JPA+Ehcache实现CRUD操作

SpringBoot系列(十)单元测试

Spring MVC – 单元测试和集成测试

Springboot 中使用单元测试

内存数据库-H2简介与实践

H2数据库攻略

H2 Features

How to disable Eureka and Spring Cloud Config in a WebMvcTest?

How to selectively disable Eureka discovery client with Spring?

使用 Spring 进行单元测试

JUnit中按照顺序执行测试方式

使用MockMvc进行Junit单元测试

SpringMVC单元测试-MockMvc

MockMVC - 基于RESTful风格的SpringMVC的测试

Spring Boot 的单元测试和集成测试

Lombok与javaFaker的使用,解放劳动力

java测试造数据神器JavaFaker

使用com.jayway.jsonpath.JsonPath包进行JSON的快速解析、设置值需要注意的性能提升方法

一款好用的json解析工具,JsonPath

源代码

https://gitee.com/cckevincyh/spring-cloud-demo/tree/int-test/

【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 Spring Boot Test集成测试环境搭建相关推荐

  1. 从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建

    从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建 本文简介 为什么使用Spring Boot 搭建怎样一个环境 开发环境 导入快速启动 ...

  2. spring boot+mybatis框架环境搭建

    配置spring boot+mybatis框架环境搭建 一, spring boot 环境搭建 以下步骤为 1,新建maven工程 2.在pom文件中添加: spring-boot-starter-p ...

  3. MAVEN集成测试环境搭建

    1. MAVEN + SVN + HUDSON + SONAR集成测试环境搭建. 1.1 软件准备 Hudson.Jenkins.Sonar 1.2 软件安装 说明:本例均使用将应用程序部署至web容 ...

  4. pybullet机器人仿真环境搭建 1.安装pybullet,测试官方示例,基础环境搭建

    pybullet机器人仿真环境搭建 1.安装pybullet 前言 安装 测试官方示例 基础环境搭建 导入pybullet 创建服务端 (可选)配置图形GUI 添加资源路径 设置重力 加载模型 迭代运 ...

  5. 用JIRA管理你的项目——(一)JIRA环境搭建

    JIRA,大家应该都已经不陌生了!  最初接触这个工具的时候,我还在一味地单纯依靠SVN管理代码,幻想着SVN可以有个邮件通知,至少在项目成员进行代码修改的时候,我可以第一时间通过邮件获得这个消息!  ...

  6. spring源码解读系列(八):观察者模式--spring监听器详解

    一.前言 在前面的文章spring源码解读系列(七)中,我们继续剖析了spring的核心refresh()方法中的registerBeanPostProcessors(beanFactory)(完成B ...

  7. 寒武纪加速平台(MLU200系列) 摸鱼指南(二)--- 模型移植-环境搭建

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 环境说明 Ubuntu 18.04 MLU270 加速卡一张 前 ...

  8. esp32 linux内核,【小狂系列】跟着小狂玩ESP32之编译环境搭建篇

    本帖最后由 3guoyangyang7 于 2016-11-3 18:41 编辑 趁热要打铁,昨天发了ESP32的预告贴,今天小狂就带大家刷一刷ESP32的编译环境搭建.怎么说的,ESP32可以在多平 ...

  9. 从零搭建ES搜索服务(一)基本概念及环境搭建

    一.前言 本系列文章最终目标是为了快速搭建一个简易可用的搜索服务.方案并不一定是最优,但实现难度较低. 二.背景 近期公司在重构老系统,需求是要求知识库支持全文检索. 我们知道普通的数据库 like ...

最新文章

  1. Ipython的Window与Linux详细安装
  2. R语言函数:length计算长度、seq生成数据序列、rep将数据对象重复N遍复制、cut将连续变量分割为多水平的因子变量、pretty将连续变量x分成n个区间创建合适的断点、cat数据对象拼接
  3. 【S1官方核心】18128核心纯净雅黑H大全力打造的1.9精品
  4. 打开chm文件不能显示内容的解决办法
  5. 全栈Python 必备库
  6. SAP CRM enterprise search index调试细节
  7. c# 访问修饰符的访问权限
  8. ubuntu命令行登录
  9. swiper链接href无效
  10. C和C++结构体区别
  11. 信息学奥赛C++语言:幸运奶牛
  12. 你的数仓函数结果不稳定,可能是属性指定错了
  13. 25岁,欠债47万怎么办
  14. 找出2n+1个数中不成对的那个
  15. Mac电脑怎么使用ping命令
  16. 1031. 高一学堂 (at)
  17. 8255芯片控制发光二极管模拟步进电机汇编实验
  18. docker ps 命令显示格式化和显示完整信息
  19. 【SpringBoot】12.SpringBoot整合Dubbo+Zookeeper
  20. 计算机网络——移动IP

热门文章

  1. github使用tokens的方法
  2. C语言中定义bool类型
  3. 【期刊】应用数学领域期刊调研
  4. 用python绘制一个螺旋正方形
  5. 【深度思考】快来看看这些方案,附答案
  6. ClickOnce管理员启动并且支持ClickOnce更新
  7. 什么是DICOM以及DICOM如何运作
  8. 利用客户端js实现汉字简体繁体转换
  9. 小米Pro14 2021款和联想小新Air14Plus选哪个
  10. java 过滤器执行图_「filterchain」java 过滤器Filter中chain.doFilter()之前和之后代码的执行顺序 - seo实验室...