Skip to content

Commit 6a3d248

Browse files
QilongZhangkhotyn
authored andcommitted
Add test sofa boot starter
Add test sofa boot starter to support run JUnit test with class isolation.
1 parent 9c7f343 commit 6a3d248

20 files changed

Lines changed: 779 additions & 8 deletions

File tree

‎pom.xml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<module>infra-sofa-boot-starter</module>
4141
<module>healthcheck-sofa-boot-starter</module>
4242
<module>runtime-sofa-boot-starter</module>
43-
<module>sofaboot-samples</module>
43+
<module>test-sofa-boot-starter</module>
4444
</modules>
4545

4646
<properties>
@@ -56,6 +56,7 @@
5656
<maven.gpg.pluign>1.5</maven.gpg.pluign>
5757
<cobertura.maven.plugin>2.6</cobertura.maven.plugin>
5858
<coveralls.maven.plugin>3.1.0</coveralls.maven.plugin>
59+
<main.user.dir>${user.dir}</main.user.dir>
5960
</properties>
6061

6162

@@ -76,7 +77,7 @@
7677
</executions>
7778
<configuration>
7879
<quiet>true</quiet>
79-
<header>${user.dir}/HEADER</header>
80+
<header>${main.user.dir}/HEADER</header>
8081
<includes>
8182
<include>**/src/main/java/**</include>
8283
<include>**/src/test/java/**</include>
@@ -100,7 +101,7 @@
100101
</execution>
101102
</executions>
102103
<configuration>
103-
<configFile>${user.dir}/Formatter.xml</configFile>
104+
<configFile>${main.user.dir}/Formatter.xml</configFile>
104105
<encoding>${project.encoding}</encoding>
105106
</configuration>
106107
</plugin>

‎sofaboot-dependencies/pom.xml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@
100100
<artifactId>runtime-sofa-boot-starter</artifactId>
101101
<version>${sofa.boot.version}</version>
102102
</dependency>
103+
<dependency>
104+
<groupId>com.alipay.sofa</groupId>
105+
<artifactId>test-sofa-boot-starter</artifactId>
106+
<version>${sofa.boot.version}</version>
107+
</dependency>
103108
<!-- SOFA Ark Plugin -->
104109
<dependency>
105110
<groupId>com.alipay.sofa</groupId>

‎sofaboot-samples/pom.xml‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@
3131
<version>2.3.0</version>
3232
<packaging>pom</packaging>
3333

34-
35-
<modules>
36-
<module>sofaboot-sample</module>
37-
<module>sofaboot-sample-with-isolation</module>
38-
</modules>
34+
<properties>
35+
<main.user.dir>${user.dir}/..</main.user.dir>
36+
</properties>
3937

4038
<build>
4139
<plugins>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# 如何使用 SOFABoot 类隔离能力
2+
3+
## 简介
4+
该用例工程演示如何使用 SOFABoot 类隔离能力,阅读该文档之前,建议先了解 SOFABoot 提供的类隔离框架 [SOFAArk](https://github.com/alipay/sofa-ark)
5+
6+
## 工程演示
7+
SOFABoot 提供了类隔离框架 SOFAArk,弥补了 Spring Boot 在类隔离能力上的缺失,用以解决在实际开发中常见的类冲突、包冲突问题;使用 SOFABoot 类隔离能力只需两步操作;配置 `sofa-ark-maven-plugin` 打包插件以及引入 `sofa-ark-springboot-starter` 依赖;
8+
9+
### 配置 Maven 打包插件
10+
SOFABoot 官方提供了 `Maven` 插件 - `sofa-ark-maven-plugin` ,只需要简单的配置项,即可将 Spring Boot 工程打包成标准格式规范的可执行 Ark 包,插件坐标为:
11+
12+
```java
13+
<plugin>
14+
<groupId>com.alipay.sofa</groupId>
15+
<artifactId>sofa-ark-maven-plugin</artifactId>
16+
</plugin>
17+
```
18+
19+
配置模板如下:
20+
21+
```xml
22+
build>
23+
<plugins>
24+
<plugin>
25+
<groupId>com.alipay.sofa</groupId>
26+
<artifactId>sofa-ark-maven-plugin</artifactId>
27+
<executions>
28+
<execution>
29+
<id>default-cli</id>
30+
31+
<!--goal executed to generate executable-ark-jar -->
32+
<goals>
33+
<goal>repackage</goal>
34+
</goals>
35+
36+
<configuration>
37+
<!--specify destination where executable-ark-jar will be saved, default saved to ${project.build.directory}-->
38+
<outputDirectory>./target</outputDirectory>
39+
40+
<!--default none-->
41+
<arkClassifier>executable-ark</arkClassifier>
42+
43+
<!-- all class exported by ark plugin would be resolved by ark biz in default, if
44+
configure denyImportClasses, then it would prefer to load them by ark biz itself -->
45+
<denyImportClasses>
46+
<class>com.alipay.sofa.SampleClass1</class>
47+
<class>com.alipay.sofa.SampleClass2</class>
48+
</denyImportClasses>
49+
50+
<!-- Corresponding to denyImportClasses, denyImportPackages is package-level -->
51+
<denyImportPackages>
52+
<package>com.alipay.sofa</package>
53+
<package>org.springframework</package>
54+
</denyImportPackages>
55+
56+
<!-- denyImportResources can prevent resource exported by ark plugin with accurate
57+
name to be resolved -->
58+
<denyImportResources>
59+
<resource>META-INF/spring/test1.xml</resource>
60+
<resource>META-INF/spring/test2.xml</resource>
61+
</denyImportResources>
62+
</configuration>
63+
</execution>
64+
</executions>
65+
</plugin>
66+
</plugins>
67+
</build>
68+
```
69+
插件配置项解释:
70+
71+
+ `outputDirectory`: 执行 `mvn package` 命令后,指定打出来的 ark 包存放目录,默认存放至 ${project.build.directory}
72+
+ `arkClassifier`: 执行 `mvn depleoy` 命令后,指定发布到仓库的 ark 包的maven坐标的 `classifer` 值, 默认为空;我们推荐配置此配置项用于和普通的 Fat Jar 加以名字上区别;
73+
+ `denyImportClasses`: 默认情况下,应用会优先加载 ark plugin 导出的类,使用该配置项,可以禁止应用从 ark plugin 加载其导出类;
74+
+ `denyImportPackages`: 对应上述的 `denyImportClasses`, 提供包级别的禁止导入;
75+
+ `denyImportResources`: 默认情况下,应用会优先加载 ark plugin 导出的资源,使用该配置项,可以禁止应用从 ark plugin 加载其导出资源;
76+
77+
需要指出的是:该插件配置只负责打包、发布 ark 包,如果需要在 ide 中启动 SOFAArk 容器或者在 SOFAArk 容器之上运行测试用例,需要额外添加类隔离框架依赖;
78+
79+
## 添加类隔离框架依赖
80+
81+
在实际开发中,为了在 SOFAArk 容器之上运行测试用例或者本地IDE中使用 SOFABoot 类隔离能力,需要引入如下依赖:
82+
83+
```xml
84+
<dependency>
85+
<groupId>com.alipay.sofa</groupId>
86+
<artifactId>sofa-ark-springboot-starter</artifactId>
87+
</dependency>
88+
```
89+
90+
### 编写测试用例
91+
Spring Boot 官方提供了和 JUnit4 集成的 `SpringRunner`,用于集成测试用例的编写;为了方便运行测试用例时使用 SOFABoot 类隔离能力,应用需要额外引入如下测试依赖:
92+
93+
```xml
94+
<dependency>
95+
<groupId>com.alipay.sofa</groupId>
96+
<artifactId>test-sofa-boot-starter</artifactId>
97+
</dependency>
98+
```
99+
100+
SOFABoot 推荐使用 `SofaBootRunner` 替代 `SpringRunner` 编写集成测试用例,使用 `SofaJUnit4Runner` 替代 `JUnit4` 编写单元测试;这样做的好处是,只需要控制添加或者删除类隔离依赖:
101+
102+
```xml
103+
<dependency>
104+
<groupId>com.alipay.sofa</groupId>
105+
<artifactId>sofa-ark-springboot-starter</artifactId>
106+
</dependency>
107+
```
108+
109+
即可完成 SOFABoot 类隔离能力的集成和剥离,使用详情如下:
110+
111+
#### SofaBootRunner
112+
集成测试示例代码:
113+
114+
```java
115+
@RunWith(SofaBootRunner.class)
116+
@SpringBootTest(classes = SofaBootClassIsolationDemoApplication.class)
117+
public class IntegrationTestCaseWithIsolation {
118+
119+
@Autowired
120+
private SampleService sampleService;
121+
122+
@Test
123+
public void test() {
124+
Assert.assertTrue("service".equals(sampleService.service()));
125+
}
126+
127+
}
128+
```
129+
130+
`SofaBootRunner` 会检测应用是否引入
131+
132+
```xml
133+
<dependency>
134+
<groupId>com.alipay.sofa</groupId>
135+
<artifactId>sofa-ark-springboot-starter</artifactId>
136+
</dependency>
137+
```
138+
139+
依赖;根据 Spring Boot 依赖即服务的原则,如果检测到 `sofa-ark-springboot-starter` 依赖,`SofaBootRunner` 会使用 SOFABoot 类隔离能力,否则和原生的 `SpringRunner` 无异;
140+
141+
#### SofaJUnit4Runner
142+
示例代码:
143+
144+
```java
145+
@RunWith(SofaJUnit4Runner.class)
146+
public class UnitTestCaseWithIsolation {
147+
public static final String testClassloader = "com.alipay.sofa.ark.container.test.TestClassLoader";
148+
149+
@Test
150+
public void test() {
151+
ClassLoader currentClassLoader = this.getClass().getClassLoader();
152+
Assert.assertTrue(currentClassLoader.getClass().getCanonicalName().equals(testClassloader));
153+
}
154+
}
155+
```
156+
157+
`SofaJUnit4Runner` 同样会检测应用是否引入 `sofa-ark-springboot-starter` 依赖;根据 Spring Boot 依赖即服务的原则,如果检测到 `sofa-ark-springboot-starter` 依赖,`SofaJUnit4Runner` 会使用 SOFABoot 类隔离能力,否则和原生的 `JUnit4` 无异;
158+
159+
#### 自定义 Runner
160+
在编写测试用例时,有时需要指定特殊的 Runner,为了统一编码风格,可以借助注解 `@DelegateToRunner` 配合 `SofaBootRunner` 和 `SofaJUnit4Runner` 使用,示例代码:
161+
162+
```java
163+
@RunWith(SofaJUnit4Runner.class)
164+
@DelegateToRunner(BlockJUnit4ClassRunner.class)
165+
public class UnitTestCaseWithoutArk {
166+
167+
@Test
168+
public void test() {
169+
Assert.assertFalse(true);
170+
}
171+
172+
}
173+
```
174+
175+
相当于如下使用
176+
177+
```java
178+
@RunWith(BlockJUnit4ClassRunner.class)
179+
public class UnitTestCaseWithoutArk {
180+
181+
@Test
182+
public void test() {
183+
Assert.assertFalse(true);
184+
}
185+
186+
}
187+
```
188+
189+

‎sofaboot-samples/sofaboot-sample-with-isolation/pom.xml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
<artifactId>sofaboot-sample-with-isolation</artifactId>
3030
<version>2.3.0</version>
3131

32+
<properties>
33+
<main.user.dir>${user.dir}/../..</main.user.dir>
34+
</properties>
35+
3236
<dependencies>
3337

3438
<!-- import SOFABoot Dependency healthcheck and infra -->
@@ -62,6 +66,12 @@
6266
<scope>test</scope>
6367
</dependency>
6468

69+
<dependency>
70+
<groupId>com.alipay.sofa</groupId>
71+
<artifactId>test-sofa-boot-starter</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
6575
</dependencies>
6676

6777
<build>

‎sofaboot-samples/sofaboot-sample-with-isolation/src/main/java/com/alipay/sofa/boot/examples/demo/isolation/SofaBootClassIsolationDemoApplication.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
import org.springframework.boot.SpringApplication;
2020
import org.springframework.boot.autoconfigure.SpringBootApplication;
21+
import org.springframework.context.annotation.ComponentScan;
2122

2223
@SpringBootApplication
24+
@ComponentScan({ "com.alipay.sofa.boot.examples.demo.service" })
2325
public class SofaBootClassIsolationDemoApplication {
2426

2527
public static void main(String[] args) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.alipay.sofa.boot.examples.demo.service;
18+
19+
/**
20+
* @author qilong.zql
21+
* @since 2.3.0
22+
*/
23+
public interface SampleService {
24+
String service();
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.alipay.sofa.boot.examples.demo.service;
18+
19+
import org.springframework.stereotype.Service;
20+
21+
/**
22+
* @author qilong.zql
23+
* @since 2.3.0
24+
*/
25+
@Service("sampleService")
26+
public class SampleServiceImpl implements SampleService {
27+
@Override
28+
public String service() {
29+
return "service";
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.alipay.sofa.boot.test;
18+
19+
import com.alipay.sofa.boot.examples.demo.isolation.SofaBootClassIsolationDemoApplication;
20+
import com.alipay.sofa.boot.examples.demo.service.SampleService;
21+
import com.alipay.sofa.test.runner.SofaBootRunner;
22+
import org.junit.Assert;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
28+
/**
29+
* @author qilong.zql
30+
* @since 2.3.0
31+
*/
32+
@RunWith(SofaBootRunner.class)
33+
@SpringBootTest(classes = SofaBootClassIsolationDemoApplication.class)
34+
public class IntegrationTestCaseRunWithIsolation {
35+
36+
@Autowired
37+
private SampleService sampleService;
38+
39+
@Test
40+
public void test() {
41+
Assert.assertTrue("service".equals(sampleService.service()));
42+
}
43+
44+
}

0 commit comments

Comments
 (0)