Browse Source

单元测试

yufeng0528 4 years ago
parent
commit
2345f4c40c

+ 13 - 4
README.md

@@ -11,9 +11,9 @@ spring5 -> webflux ->spring gateway
11
 * 2.0.* -> Finchley
11
 * 2.0.* -> Finchley
12
 
12
 
13
 ## 路由配置参考
13
 ## 路由配置参考
14
-1. https://www.jianshu.com/p/86660b8b24c4
15
-2. https://www.jdon.com/51642
16
-3. 
14
+1. [https://www.jianshu.com/p/86660b8b24c4](https://www.jianshu.com/p/86660b8b24c4)
15
+2. [https://www.jdon.com/51642](https://www.jdon.com/51642)
16
+3.  
17
 
17
 
18
 ## gateway filter
18
 ## gateway filter
19
 1. AddRequestHeader 添加header给下流接口
19
 1. AddRequestHeader 添加header给下流接口
@@ -36,7 +36,16 @@ spring5 -> webflux ->spring gateway
36
 
36
 
37
 ## 全局过滤器
37
 ## 全局过滤器
38
 1. ReactiveLoadBalancerClientFilter
38
 1. ReactiveLoadBalancerClientFilter
39
-2. Gateway Metrics 
39
+2. Gateway Metrics
40
+3. 
41
+
42
+## 单元测试
43
+1. wiremock
44
+2. [https://www.infoq.com/articles/stubbing-mocking-service-virtualization-differences](https://www.infoq.com/articles/stubbing-mocking-service-virtualization-differences/)
45
+
46
+## 其他
47
+1. spring.cloud.gateway.discovery.locator.enabled=true
48
+2. actuator 配置
40
 3. 
49
 3. 
41
 
50
 
42
 
51
 

+ 42 - 1
pom.xml

@@ -79,8 +79,49 @@
79
 			<groupId>org.springframework.boot</groupId>
79
 			<groupId>org.springframework.boot</groupId>
80
 			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
80
 			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
81
 		</dependency>
81
 		</dependency>
82
-
83
 		
82
 		
83
+		<!-- Spring test 依赖 -->
84
+        <dependency>
85
+            <groupId>org.springframework.boot</groupId>
86
+            <artifactId>spring-boot-starter-test</artifactId>
87
+            <scope>test</scope>
88
+        </dependency>
89
+        
90
+        <dependency>
91
+            <groupId>junit</groupId>
92
+            <artifactId>junit</artifactId>
93
+            <scope>test</scope>
94
+        </dependency>
95
+        
96
+        <!-- 集成wireMock来实现mock请求响应。wireMock会自动构建一个虚拟远程服务 -->
97
+		<dependency>
98
+		   <groupId>org.springframework.cloud</groupId>
99
+		   <artifactId>spring-cloud-contract-wiremock</artifactId>
100
+		   <scope>test</scope>
101
+		</dependency>
102
+		
103
+		<!-- 提供打包预定义数据服务 -->
104
+		<dependency>
105
+		   <groupId>org.springframework.cloud</groupId>
106
+		   <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
107
+		   <scope>test</scope>
108
+		</dependency>
109
+		
110
+		<!-- 自动生成单元测试代码 -->
111
+		<dependency>
112
+		   <groupId>org.springframework.cloud</groupId>
113
+		   <artifactId>spring-cloud-starter-contract-verifier</artifactId>
114
+		   <scope>test</scope>
115
+		</dependency>
116
+
117
+
118
+		<dependency>
119
+			<groupId>com.github.tomakehurst</groupId>
120
+			<artifactId>wiremock-standalone</artifactId>
121
+			<version>2.18.0</version>
122
+			<scope>test</scope>
123
+		</dependency>
124
+
84
 		<!-- lombok依赖包 -->
125
 		<!-- lombok依赖包 -->
85
 		<dependency>
126
 		<dependency>
86
 			<groupId>org.projectlombok</groupId>
127
 			<groupId>org.projectlombok</groupId>

+ 6 - 0
src/main/java/com/yaozhitech/spring5/App.java

@@ -2,7 +2,12 @@ package com.yaozhitech.spring5;
2
 
2
 
3
 import org.springframework.boot.SpringApplication;
3
 import org.springframework.boot.SpringApplication;
4
 import org.springframework.boot.autoconfigure.SpringBootApplication;
4
 import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
5
 
6
 
7
+import com.yaozhitech.spring5.config.UriConfiguration;
8
+
9
+
10
+@EnableConfigurationProperties(UriConfiguration.class)
6
 @SpringBootApplication
11
 @SpringBootApplication
7
 public class App {
12
 public class App {
8
 
13
 
@@ -10,4 +15,5 @@ public class App {
10
         // 程序启动入口
15
         // 程序启动入口
11
         SpringApplication.run(App.class,args);
16
         SpringApplication.run(App.class,args);
12
     }
17
     }
18
+	
13
 }
19
 }

+ 6 - 3
src/main/java/com/yaozhitech/spring5/config/RouterConfig.java

@@ -12,19 +12,22 @@ import reactor.core.publisher.Mono;
12
 @Configuration
12
 @Configuration
13
 public class RouterConfig {
13
 public class RouterConfig {
14
 	
14
 	
15
+	
16
+	
15
 	@Bean
17
 	@Bean
16
-	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
18
+	public RouteLocator customRouteLocator(RouteLocatorBuilder builder, UriConfiguration uriConfiguration) {
19
+		String httpUri = uriConfiguration.getHttpbin();
17
 		//@formatter:off
20
 		//@formatter:off
18
 		return builder.routes()
21
 		return builder.routes()
19
 				.route("path_route", r -> r.path("/city_list.do")
22
 				.route("path_route", r -> r.path("/city_list.do")
20
 						.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()).setKeyResolver(urlPathKeyResolver())))
23
 						.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()).setKeyResolver(urlPathKeyResolver())))
21
-						.uri("https://api.bbztx.com"))
24
+						.uri(httpUri))
22
 				.route("host_route", r -> r.host("*.myhost.org")
25
 				.route("host_route", r -> r.host("*.myhost.org")
23
 						.uri("http://httpbin.org"))
26
 						.uri("http://httpbin.org"))
24
 				.route("rewrite_route", r -> r.path("/city_list")
27
 				.route("rewrite_route", r -> r.path("/city_list")
25
 						.filters(f -> f.rewritePath("city_list",  // rewritePath方法会使用内建的过滤器重写路径
28
 						.filters(f -> f.rewritePath("city_list",  // rewritePath方法会使用内建的过滤器重写路径
26
 								"city_list.do"))
29
 								"city_list.do"))
27
-						.uri("https://api.bbztx.com"))
30
+						.uri(httpUri))
28
 //				.route("hystrix_fallback_route", r -> r.path("/slow_query.do")
31
 //				.route("hystrix_fallback_route", r -> r.path("/slow_query.do")
29
 //						.filters(f -> f
32
 //						.filters(f -> f
30
 //										.rewritePath("_query.do", "")
33
 //										.rewritePath("_query.do", "")

+ 17 - 0
src/main/java/com/yaozhitech/spring5/config/UriConfiguration.java

@@ -0,0 +1,17 @@
1
+package com.yaozhitech.spring5.config;
2
+
3
+import org.springframework.boot.context.properties.ConfigurationProperties;
4
+
5
+@ConfigurationProperties
6
+public class UriConfiguration {
7
+
8
+	private String httpbin = "https://api.bbztx.com";
9
+
10
+	public String getHttpbin() {
11
+		return httpbin;
12
+	}
13
+
14
+	public void setHttpbin(String httpbin) {
15
+		this.httpbin = httpbin;
16
+	}
17
+}

+ 70 - 0
src/test/java/com/yaozhitech/spring5/ApplicationTest.java

@@ -0,0 +1,70 @@
1
+package com.yaozhitech.spring5;
2
+
3
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
5
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
6
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
7
+import static org.assertj.core.api.Assertions.assertThat;
8
+
9
+import org.junit.Before;
10
+import org.junit.Test;
11
+import org.junit.runner.RunWith;
12
+import org.springframework.beans.factory.annotation.Autowired;
13
+import org.springframework.boot.test.context.SpringBootTest;
14
+import org.springframework.boot.web.server.LocalServerPort;
15
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
16
+import org.springframework.test.context.junit4.SpringRunner;
17
+import org.springframework.test.web.reactive.server.WebTestClient;
18
+
19
+
20
+@RunWith(SpringRunner.class)
21
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
22
+        properties = {"httpbin=http://localhost:${wiremock.server.port}"})
23
+@AutoConfigureWireMock(port = 0)
24
+public class ApplicationTest {
25
+
26
+	@Autowired
27
+    private WebTestClient webClient;
28
+	
29
+	@LocalServerPort
30
+    private int port;
31
+
32
+    @Before
33
+    public void setUp() throws Exception {
34
+        System.out.println(String.format("port is : [%d]", port));
35
+    }
36
+
37
+    @Test
38
+    public void contextLoads() throws Exception {
39
+        //Stubs
40
+        stubFor(get(urlEqualTo("/get"))
41
+                .willReturn(aResponse()
42
+                    .withBody("{\"headers\":{\"Hello\":\"World\"}}")
43
+                    .withHeader("Content-Type", "application/json")));
44
+        stubFor(get(urlEqualTo("/delay/3"))
45
+            .willReturn(aResponse()
46
+                .withBody("no fallback")
47
+                .withFixedDelay(3000)));
48
+        
49
+        stubFor(get(urlEqualTo("/city_list.do"))
50
+                .willReturn(aResponse()
51
+                    .withBody("{}")
52
+                    .withFixedDelay(100)));
53
+
54
+//        webClient
55
+//            .get().uri("/get")
56
+//            .exchange()
57
+//            .expectStatus().isOk()
58
+//            .expectBody()
59
+//            .jsonPath("$.headers.Hello").isEqualTo("World");
60
+
61
+        webClient
62
+            .get().uri("/city_list")
63
+//            .header("Host", "www.hystrix.com")
64
+            .exchange()
65
+            .expectStatus().isOk()
66
+            .expectBody()
67
+            .consumeWith(
68
+                response -> assertThat(response.getResponseBody()).isEqualTo("{}".getBytes()));
69
+    }
70
+}