├── .gitignore
├── LICENSE
├── README.md
├── annotation
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── chanjar
│ │ │ └── annotation
│ │ │ ├── activeprofiles
│ │ │ ├── Bar.java
│ │ │ ├── Config.java
│ │ │ └── Foo.java
│ │ │ ├── overrideac
│ │ │ └── AutoConfigurationEnableLogger.java
│ │ │ └── testconfig
│ │ │ └── Foo.java
│ └── resources
│ │ └── META-INF
│ │ └── spring.factories
│ └── test
│ ├── java
│ └── me
│ │ └── chanjar
│ │ └── annotation
│ │ ├── activeprofiles
│ │ ├── ex1
│ │ │ └── ActiveProfileTest.java
│ │ └── ex2
│ │ │ └── ActiveProfileTest.java
│ │ ├── jsontest
│ │ ├── ex1
│ │ │ ├── Foo.java
│ │ │ └── SimpleJsonTest.java
│ │ ├── ex2
│ │ │ ├── FooJsonComponent.java
│ │ │ └── JsonComponentJacksonTest.java
│ │ └── ex3
│ │ │ └── ThinJsonTest.java
│ │ ├── overrideac
│ │ ├── ex1
│ │ │ └── BootTest.java
│ │ └── ex2
│ │ │ └── BootTest.java
│ │ ├── testconfig
│ │ ├── ex1
│ │ │ └── TestConfigurationTest.java
│ │ ├── ex2
│ │ │ ├── Config.java
│ │ │ ├── TestConfig.java
│ │ │ └── TestConfigurationTest.java
│ │ └── ex3
│ │ │ ├── ExcludeConfig1.java
│ │ │ ├── ExcludeConfig2.java
│ │ │ ├── IncludeConfig.java
│ │ │ ├── TestConfig.java
│ │ │ ├── TestConfigExclude_1_Test.java
│ │ │ ├── TestConfigExclude_2_Test.java
│ │ │ └── TestConfigIncludedTest.java
│ │ └── testps
│ │ ├── ex1
│ │ ├── PropertySourceConfig.java
│ │ └── TestPropertyTest.java
│ │ └── ex2
│ │ └── TestPropertyTest.java
│ └── resources
│ └── me
│ └── chanjar
│ └── annotation
│ ├── jsontest
│ └── ex1
│ │ └── expected.json
│ └── testps
│ └── ex1
│ ├── property-source.properties
│ └── test-property-source.properties
├── aop
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── chanjar
│ │ └── aop
│ │ ├── aspect
│ │ └── FooAspect.java
│ │ ├── config
│ │ └── AopConfig.java
│ │ └── service
│ │ ├── FooService.java
│ │ └── FooServiceImpl.java
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ └── aop
│ ├── ex1
│ └── SpringAop_1_Test.java
│ ├── ex2
│ └── SpringAop_2_Test.java
│ └── ex3
│ └── SpringBootAopTest.java
├── appendix_i.md
├── appendix_ii.md
├── basic
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── chanjar
│ │ └── basic
│ │ └── service
│ │ ├── FooService.java
│ │ └── FooServiceImpl.java
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ └── basic
│ ├── spring
│ ├── ex1
│ │ └── FooServiceImplTest.java
│ ├── ex2
│ │ └── FooServiceImplTest.java
│ └── ex3
│ │ ├── Config.java
│ │ └── FooServiceImplTest.java
│ ├── springboot
│ ├── ex1
│ │ └── FooServiceImplTest.java
│ ├── ex2
│ │ └── FooServiceImplTest.java
│ ├── ex3
│ │ ├── Config.java
│ │ └── FooServiceImplTest.java
│ ├── ex4
│ │ ├── Config.java
│ │ └── FooServiceImplTest.java
│ ├── ex5
│ │ ├── Config.java
│ │ └── FooServiceImplTest.java
│ └── ex6
│ │ ├── Config.java
│ │ └── FooServiceImplTest.java
│ └── testng
│ └── ex1
│ └── FooServiceImplTest.java
├── chapter_0_concept.md
├── chapter_1_intro.md
├── chapter_1_s1_testng.md
├── chapter_1_s2_spring_testing.md
├── chapter_1_s3_spring_boot_testing.md
├── chapter_2_intro.md
├── chapter_2_s1_test_property_source.md
├── chapter_2_s2_active_profile.md
├── chapter_2_s3_json_test.md
├── chapter_2_s4_override_auto_configuration.md
├── chapter_2_s5_test_configuration.md
├── chapter_3_mockito.md
├── chapter_4_s1_basic.md
├── chapter_4_s2_using_docker.md
├── chapter_5_mvc.md
├── chapter_6_aop.md
├── chapter_7_configuration.md
├── chapter_8_share_test_config.md
├── configuration
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── chanjar
│ │ └── configuration
│ │ └── service
│ │ ├── Bar.java
│ │ └── Foo.java
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ └── configuration
│ ├── ex1
│ ├── FooConfiguration.java
│ └── FooConfigurationTest.java
│ ├── ex2
│ ├── FooConfiguration.java
│ └── FooConfigurationTest.java
│ ├── ex3
│ ├── FooConfiguration.java
│ └── FooConfigurationTest.java
│ └── ex4
│ ├── BarConfiguration.java
│ └── BarConfigurationTest.java
├── mock
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── chanjar
│ │ └── common
│ │ ├── Bar.java
│ │ ├── Foo.java
│ │ └── FooImpl.java
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ ├── mockito
│ └── MockitoTest.java
│ ├── no_mock
│ └── NoMockTest.java
│ ├── spring1
│ └── Spring_1_Test.java
│ ├── spring2
│ ├── Loo.java
│ ├── LooImpl.java
│ └── Spring_2_Test.java
│ └── springboot1
│ └── Boot_1_Test.java
├── mvc
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── chanjar
│ │ └── web
│ │ ├── Foo.java
│ │ ├── FooController.java
│ │ └── FooImpl.java
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ ├── spring1
│ └── SpringMvc_1_Test.java
│ ├── spring2
│ └── SpringMvc_2_Test.java
│ ├── springboot1
│ └── BootMvc_1_Test.java
│ └── springboot2
│ └── BootMvc_2_Test.java
├── pom.xml
├── rdbs-docker
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── chanjar
│ │ │ └── domain
│ │ │ ├── Foo.java
│ │ │ ├── FooRepository.java
│ │ │ └── FooRepositoryImpl.java
│ └── resources
│ │ └── db
│ │ └── migration
│ │ └── V1.0.0__foo-ddl.sql
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ └── domain
│ ├── FooRepositoryImplIT.java
│ └── FooTest.java
├── rdbs
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── chanjar
│ │ │ └── domain
│ │ │ ├── Foo.java
│ │ │ ├── FooRepository.java
│ │ │ └── FooRepositoryImpl.java
│ └── resources
│ │ ├── db
│ │ └── migration
│ │ │ └── V1.0.0__foo-ddl.sql
│ │ └── me
│ │ └── chanjar
│ │ └── domain
│ │ └── foo-ddl.sql
│ └── test
│ └── java
│ └── me
│ └── chanjar
│ ├── spring1
│ ├── Spring_1_IT.java
│ ├── Spring_1_IT_Configuration.java
│ └── index.jsp
│ ├── spring2
│ ├── Spring_2_IT.java
│ └── Spring_2_IT_Configuration.java
│ └── springboot1
│ └── Boot_1_IT.java
└── share-config
├── pom.xml
└── src
├── main
├── java
│ └── me
│ │ └── chanjar
│ │ └── shareconfig
│ │ ├── config
│ │ └── FooRepositoryConfiguration.java
│ │ └── service
│ │ ├── Foo.java
│ │ ├── FooRepository.java
│ │ └── FooRepositoryImpl.java
└── resources
│ └── db
│ └── migration
│ └── V1.0.0__foo-ddl.sql
└── test
└── java
└── me
└── chanjar
└── shareconfig
├── annotation
└── FooRepositoryIT.java
├── configuration
└── FooRepositoryIT.java
├── inter
└── FooRepositoryIT.java
├── service
└── FooRepositoryTestBase.java
└── testconfig
├── AnnotationConfiguration.java
├── InterfaceConfiguration.java
└── PlainConfiguration.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.ear
17 | *.zip
18 | *.tar.gz
19 | *.rar
20 |
21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
22 | hs_err_pid*
23 |
24 | target
25 | *.iml
26 | .project
27 | .classpath
28 | .settings
29 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring、Spring Boot和TestNG测试指南
2 |
3 | Spring、Spring Boot都提供了非常便利的测试工具,但遗憾的是官方文档的大多数例子都是基于JUnit的。本人比较喜欢用TestNG做单元、集成测试,所以开启了本项目收集了在Spring、Spring Boot项目中利用TestNG测试的例子。
4 |
5 | ## 章节列表
6 |
7 | 1. [Chapter 0: 基本概念][chapter_0_concept]
8 | 1. Chapter 1: 基本用法
9 | 1. [引言][chapter_1_intro]
10 | 1. [认识TestNG][chapter_1_s1_testng]
11 | 1. [使用Spring Testing工具][chapter_1_s2_spring_testing]
12 | 1. [使用Spring Boot Testing工具][chapter_1_s3_spring_boot_testing]
13 | 1. Chapter 2: Annotations
14 | 1. [引言][chapter_2_intro]
15 | 1. [@TestPropertySource][chapter_2_s1_test_property_source]
16 | 1. [@ActiveProfile][chapter_2_s2_active_profile]
17 | 1. [@JsonTest][chapter_2_s3_json_test]
18 | 1. [@OverrideAutoConfiguration][chapter_2_s4_override_auto_configuration]
19 | 1. [@TestConfiguration][chapter_2_s5_test_configuration]
20 | 1. [Chapter 3: 使用Mockito][chapter_3_mockito]
21 | 1. Chapter 4: 测试关系型数据库
22 | 1. [基本做法][chapter_4_s1_basic]
23 | 1. [使用Docker创建临时数据库][chapter_4_s2_using_docker]
24 | 1. [Chapter 5: 测试Spring MVC][chapter_5_mvc]
25 | 1. [Chapter 6: 测试AOP][chapter_6_aop]
26 | 1. [Chapter 7: 测试@Configuration][chapter_7_configuration]
27 | 1. [Chapter 8: 共享测试配置][chapter_8_share_test_config]
28 | 1. [附录I Spring Mock Objects][appendix_i]
29 | 1. [附录II Spring Test Utils][appendix_ii]
30 |
31 |
32 | [doc-spring-test-utils]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#unit-testing-support-classes
33 | [chapter_0_concept]: chapter_0_concept.md
34 |
35 | [chapter_1_intro]: chapter_1_intro.md
36 | [chapter_1_s1_testng]: chapter_1_s1_testng.md
37 | [chapter_1_s2_spring_testing]: chapter_1_s2_spring_testing.md
38 | [chapter_1_s3_spring_boot_testing]: chapter_1_s3_spring_boot_testing.md
39 |
40 | [chapter_2_intro]: chapter_2_intro.md
41 | [chapter_2_s1_test_property_source]: chapter_2_s1_test_property_source.md
42 | [chapter_2_s2_active_profile]: chapter_2_s2_active_profile.md
43 | [chapter_2_s3_json_test]: chapter_2_s3_json_test.md
44 | [chapter_2_s4_override_auto_configuration]: chapter_2_s4_override_auto_configuration.md
45 | [chapter_2_s5_test_configuration]: chapter_2_s5_test_configuration.md
46 |
47 | [chapter_3_mockito]: chapter_3_mockito.md
48 |
49 | [chapter_4_s1_basic]: chapter_4_s1_basic.md
50 | [chapter_4_s2_using_docker]: chapter_4_s2_using_docker.md
51 |
52 | [chapter_5_mvc]: chapter_5_mvc.md
53 | [chapter_6_aop]: chapter_6_aop.md
54 | [chapter_7_configuration]: chapter_7_configuration.md
55 | [chapter_8_share_test_config]: chapter_8_share_test_config.md
56 | [appendix_i]: appendix_i.md
57 | [appendix_ii]: appendix_ii.md
58 |
--------------------------------------------------------------------------------
/annotation/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-annotation
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-autoconfigure
26 |
27 |
28 |
29 | org.springframework
30 | spring-web
31 |
32 |
33 |
34 | org.slf4j
35 | slf4j-api
36 |
37 |
38 |
39 | ch.qos.logback
40 | logback-classic
41 |
42 |
43 |
44 | org.apache.commons
45 | commons-lang3
46 |
47 |
48 |
49 | org.apache.commons
50 | commons-collections4
51 |
52 |
53 |
54 | joda-time
55 | joda-time
56 |
57 |
58 |
59 | com.fasterxml.jackson.core
60 | jackson-core
61 |
62 |
63 |
64 | com.fasterxml.jackson.core
65 | jackson-databind
66 |
67 |
68 |
69 | com.fasterxml.jackson.datatype
70 | jackson-datatype-joda
71 |
72 |
73 |
74 | com.fasterxml.jackson.datatype
75 | jackson-datatype-jsr310
76 |
77 |
78 |
79 |
80 |
81 | org.testng
82 | testng
83 | test
84 |
85 |
86 |
87 | org.springframework.boot
88 | spring-boot-starter-test
89 | test
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | org.apache.maven.plugins
98 | maven-jar-plugin
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/annotation/src/main/java/me/chanjar/annotation/activeprofiles/Bar.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.activeprofiles;
2 |
3 | public class Bar {
4 |
5 | private final String name;
6 |
7 | public Bar(String name) {
8 | this.name = name;
9 | }
10 |
11 | public String getName() {
12 | return name;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/annotation/src/main/java/me/chanjar/annotation/activeprofiles/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.activeprofiles;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.Profile;
6 |
7 | @Configuration
8 | public class Config {
9 |
10 | @Bean
11 | @Profile("dev")
12 | public Foo fooDev() {
13 | return new Foo("dev");
14 | }
15 |
16 | @Bean
17 | @Profile("product")
18 | public Foo fooProduct() {
19 | return new Foo("product");
20 | }
21 |
22 | @Bean
23 | @Profile("default")
24 | public Foo fooDefault() {
25 | return new Foo("default");
26 | }
27 |
28 | @Bean
29 | public Bar bar() {
30 | return new Bar("no profile");
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/annotation/src/main/java/me/chanjar/annotation/activeprofiles/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.activeprofiles;
2 |
3 | public class Foo {
4 |
5 | private final String name;
6 |
7 | public Foo(String name) {
8 | this.name = name;
9 | }
10 |
11 | public String getName() {
12 | return name;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/annotation/src/main/java/me/chanjar/annotation/overrideac/AutoConfigurationEnableLogger.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.overrideac;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | @Configuration
8 | public class AutoConfigurationEnableLogger {
9 |
10 | private static final Logger LOGGER = LoggerFactory.getLogger(AutoConfigurationEnableLogger.class);
11 |
12 | public AutoConfigurationEnableLogger() {
13 | LOGGER.info("Auto Configuration Enabled");
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/annotation/src/main/java/me/chanjar/annotation/testconfig/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig;
2 |
3 | public class Foo {
4 |
5 | private final String name;
6 |
7 | public Foo(String name) {
8 | this.name = name;
9 | }
10 |
11 | public String getName() {
12 | return name;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/annotation/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | me.chanjar.annotation.overrideac.AutoConfigurationEnableLogger
3 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/activeprofiles/ex1/ActiveProfileTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.activeprofiles.ex1;
2 |
3 | import me.chanjar.annotation.activeprofiles.Bar;
4 | import me.chanjar.annotation.activeprofiles.Config;
5 | import me.chanjar.annotation.activeprofiles.Foo;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.testng.Assert.assertEquals;
12 |
13 | @ContextConfiguration(classes = Config.class)
14 | public class ActiveProfileTest extends AbstractTestNGSpringContextTests {
15 |
16 | @Autowired
17 | private Foo foo;
18 |
19 | @Autowired
20 | private Bar bar;
21 |
22 | @Test
23 | public void test() {
24 | assertEquals(foo.getName(), "default");
25 | assertEquals(bar.getName(), "no profile");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/activeprofiles/ex2/ActiveProfileTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.activeprofiles.ex2;
2 |
3 | import me.chanjar.annotation.activeprofiles.Bar;
4 | import me.chanjar.annotation.activeprofiles.Config;
5 | import me.chanjar.annotation.activeprofiles.Foo;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.test.context.ActiveProfiles;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
10 | import org.testng.annotations.Test;
11 |
12 | import static org.testng.Assert.assertEquals;
13 |
14 | @ContextConfiguration(classes = Config.class)
15 | @ActiveProfiles("product")
16 | public class ActiveProfileTest extends AbstractTestNGSpringContextTests {
17 |
18 | @Autowired
19 | private Foo foo;
20 |
21 | @Autowired
22 | private Bar bar;
23 |
24 | @Test
25 | public void test() {
26 | assertEquals(foo.getName(), "product");
27 | assertEquals(bar.getName(), "no profile");
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/jsontest/ex1/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.jsontest.ex1;
2 |
3 | import org.apache.commons.lang3.builder.ToStringBuilder;
4 |
5 | /**
6 | * Created by qianjia on 2017/7/18.
7 | */
8 | public class Foo {
9 |
10 | private String name;
11 |
12 | private int age;
13 |
14 | public Foo() {
15 | }
16 |
17 | public Foo(String name, int age) {
18 | this.name = name;
19 | this.age = age;
20 | }
21 |
22 | public String getName() {
23 | return name;
24 | }
25 |
26 | public void setName(String name) {
27 | this.name = name;
28 | }
29 |
30 | public int getAge() {
31 | return age;
32 | }
33 |
34 | public void setAge(int age) {
35 | this.age = age;
36 | }
37 |
38 | @Override
39 | public boolean equals(Object o) {
40 | if (this == o) return true;
41 | if (o == null || getClass() != o.getClass()) return false;
42 |
43 | Foo foo = (Foo) o;
44 |
45 | if (age != foo.age) return false;
46 | return name != null ? name.equals(foo.name) : foo.name == null;
47 | }
48 |
49 | @Override
50 | public int hashCode() {
51 | int result = name != null ? name.hashCode() : 0;
52 | result = 31 * result + age;
53 | return result;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return new ToStringBuilder(this)
59 | .append("name", name)
60 | .append("age", age)
61 | .toString();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/jsontest/ex1/SimpleJsonTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.jsontest.ex1;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.test.autoconfigure.json.JsonTest;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.boot.test.json.JacksonTester;
7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.assertj.core.api.Assertions.assertThat;
11 |
12 | @SpringBootTest(classes = SimpleJsonTest.class)
13 | @JsonTest
14 | public class SimpleJsonTest extends AbstractTestNGSpringContextTests {
15 |
16 | @Autowired
17 | private JacksonTester json;
18 |
19 | @Test
20 | public void testSerialize() throws Exception {
21 | Foo details = new Foo("Honda", 12);
22 | // 使用通包下的json文件测试结果是否正确
23 | assertThat(this.json.write(details)).isEqualToJson("expected.json");
24 | // 或者使用基于JSON path的校验
25 | assertThat(this.json.write(details)).hasJsonPathStringValue("@.name");
26 | assertThat(this.json.write(details)).extractingJsonPathStringValue("@.name").isEqualTo("Honda");
27 | assertThat(this.json.write(details)).hasJsonPathNumberValue("@.age");
28 | assertThat(this.json.write(details)).extractingJsonPathNumberValue("@.age").isEqualTo(12);
29 | }
30 |
31 | @Test
32 | public void testDeserialize() throws Exception {
33 | String content = "{\"name\":\"Ford\",\"age\":13}";
34 | Foo actual = this.json.parseObject(content);
35 | assertThat(actual).isEqualTo(new Foo("Ford", 13));
36 | assertThat(actual.getName()).isEqualTo("Ford");
37 | assertThat(actual.getAge()).isEqualTo(13);
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/jsontest/ex2/FooJsonComponent.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.jsontest.ex2;
2 |
3 | import com.fasterxml.jackson.core.JsonGenerator;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.core.JsonToken;
7 | import com.fasterxml.jackson.databind.DeserializationContext;
8 | import com.fasterxml.jackson.databind.JsonDeserializer;
9 | import com.fasterxml.jackson.databind.JsonSerializer;
10 | import com.fasterxml.jackson.databind.SerializerProvider;
11 | import me.chanjar.annotation.jsontest.ex1.Foo;
12 | import org.springframework.boot.jackson.JsonComponent;
13 |
14 | import java.io.IOException;
15 |
16 | /**
17 | * Created by qianjia on 2017/7/19.
18 | */
19 | @JsonComponent
20 | public class FooJsonComponent {
21 |
22 | public static class Serializer extends JsonSerializer {
23 | @Override
24 | public void serialize(Foo value, JsonGenerator gen, SerializerProvider serializers)
25 | throws IOException, JsonProcessingException {
26 | gen.writeString("name=" + value.getName() + ",age=" + value.getAge());
27 | }
28 |
29 | }
30 |
31 | public static class Deserializer extends JsonDeserializer {
32 |
33 | @Override
34 | public Foo deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
35 | JsonToken t = p.getCurrentToken();
36 |
37 | if (t == JsonToken.VALUE_STRING) {
38 | String trim = p.getText().trim();
39 |
40 | String[] split = trim.split(",");
41 | Foo foo = new Foo();
42 | foo.setName(split[0].split("=")[1]);
43 | foo.setAge(Integer.parseInt(split[1].split("=")[1]));
44 | return foo;
45 | }
46 |
47 | return (Foo) ctxt.handleUnexpectedToken(handledType(), p);
48 |
49 | }
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/jsontest/ex2/JsonComponentJacksonTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.jsontest.ex2;
2 |
3 | import me.chanjar.annotation.jsontest.ex1.Foo;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.autoconfigure.json.JsonTest;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.boot.test.json.JacksonTester;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.assertj.core.api.Assertions.assertThat;
12 |
13 | @SpringBootTest(classes = { JsonComponentJacksonTest.class, FooJsonComponent.class })
14 | @JsonTest
15 | public class JsonComponentJacksonTest extends AbstractTestNGSpringContextTests {
16 |
17 | @Autowired
18 | private JacksonTester json;
19 |
20 | @Test
21 | public void testSerialize() throws Exception {
22 | Foo details = new Foo("Honda", 12);
23 | assertThat(this.json.write(details).getJson()).isEqualTo("\"name=Honda,age=12\"");
24 | }
25 |
26 | @Test
27 | public void testDeserialize() throws Exception {
28 | String content = "\"name=Ford,age=13\"";
29 | Foo actual = this.json.parseObject(content);
30 | assertThat(actual).isEqualTo(new Foo("Ford", 13));
31 | assertThat(actual.getName()).isEqualTo("Ford");
32 | assertThat(actual.getAge()).isEqualTo(13);
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/jsontest/ex3/ThinJsonTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.jsontest.ex3;
2 |
3 | import me.chanjar.annotation.jsontest.ex1.Foo;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.autoconfigure.json.JsonTest;
6 | import org.springframework.boot.test.json.JacksonTester;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.assertj.core.api.Assertions.assertThat;
12 |
13 | @JsonTest
14 | @ContextConfiguration(classes = ThinJsonTest.class)
15 | public class ThinJsonTest extends AbstractTestNGSpringContextTests {
16 |
17 | @Autowired
18 | private JacksonTester json;
19 |
20 | @Test
21 | public void testSerialize() throws Exception {
22 | Foo details = new Foo("Honda", 12);
23 | // 或者使用基于JSON path的校验
24 | assertThat(this.json.write(details)).hasJsonPathStringValue("@.name");
25 | assertThat(this.json.write(details)).extractingJsonPathStringValue("@.name").isEqualTo("Honda");
26 | assertThat(this.json.write(details)).hasJsonPathNumberValue("@.age");
27 | assertThat(this.json.write(details)).extractingJsonPathNumberValue("@.age").isEqualTo(12);
28 | }
29 |
30 | @Test
31 | public void testDeserialize() throws Exception {
32 | String content = "{\"name\":\"Ford\",\"age\":13}";
33 | Foo actual = this.json.parseObject(content);
34 | assertThat(actual).isEqualTo(new Foo("Ford", 13));
35 | assertThat(actual.getName()).isEqualTo("Ford");
36 | assertThat(actual.getAge()).isEqualTo(13);
37 |
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/overrideac/ex1/BootTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.overrideac.ex1;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
6 | import org.testng.annotations.Test;
7 |
8 | @SpringBootTest
9 | @SpringBootApplication
10 | public class BootTest extends AbstractTestNGSpringContextTests {
11 |
12 | @Test
13 | public void testName() throws Exception {
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/overrideac/ex2/BootTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.overrideac.ex2;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 | import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | @SpringBootTest
10 | @OverrideAutoConfiguration(enabled = false)
11 | @SpringBootApplication
12 | public class BootTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Test
15 | public void testName() throws Exception {
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex1/TestConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex1;
2 |
3 | import me.chanjar.annotation.testconfig.Foo;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.SpringBootConfiguration;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.boot.test.context.TestConfiguration;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
10 | import org.testng.annotations.Test;
11 |
12 | import static org.testng.Assert.assertEquals;
13 |
14 | @SpringBootTest
15 | @SpringBootConfiguration
16 | public class TestConfigurationTest extends AbstractTestNGSpringContextTests {
17 |
18 | @Autowired
19 | private Foo foo;
20 |
21 | @Test
22 | public void testPlusCount() throws Exception {
23 | assertEquals(foo.getName(), "from test config");
24 | }
25 |
26 | @TestConfiguration
27 | public class TestConfig {
28 |
29 | @Bean
30 | public Foo foo() {
31 | return new Foo("from test config");
32 | }
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex2;
2 |
3 | import me.chanjar.annotation.testconfig.Foo;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | @Configuration
8 | public class Config {
9 |
10 | @Bean
11 | public Foo foo() {
12 | return new Foo("from config");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/TestConfig.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex2;
2 |
3 | import me.chanjar.annotation.testconfig.Foo;
4 | import org.springframework.boot.test.context.TestConfiguration;
5 | import org.springframework.context.annotation.Bean;
6 |
7 | @TestConfiguration
8 | public class TestConfig {
9 |
10 | @Bean
11 | public Foo foo() {
12 | return new Foo("from test config");
13 | }
14 |
15 | @Bean
16 | public Foo foo2() {
17 | return new Foo("from test config2");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/TestConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex2;
2 |
3 | import me.chanjar.annotation.testconfig.Foo;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.annotation.Qualifier;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.testng.Assert.assertEquals;
11 |
12 | @SpringBootTest(classes = { Config.class, TestConfig.class })
13 | public class TestConfigurationTest extends AbstractTestNGSpringContextTests {
14 |
15 | @Qualifier("foo")
16 | @Autowired
17 | private Foo foo;
18 |
19 | @Qualifier("foo2")
20 | @Autowired
21 | private Foo foo2;
22 |
23 | @Test
24 | public void testPlusCount() throws Exception {
25 | assertEquals(foo.getName(), "from test config");
26 | assertEquals(foo2.getName(), "from test config2");
27 |
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/ExcludeConfig1.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.boot.SpringBootConfiguration;
4 | import org.springframework.boot.context.TypeExcludeFilter;
5 | import org.springframework.context.annotation.ComponentScan;
6 | import org.springframework.context.annotation.FilterType;
7 |
8 | @SpringBootConfiguration
9 | @ComponentScan(excludeFilters = {
10 | @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)
11 | })
12 | public interface ExcludeConfig1 {
13 | }
14 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/ExcludeConfig2.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | @SpringBootApplication
6 | public interface ExcludeConfig2 {
7 | }
8 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/IncludeConfig.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.boot.SpringBootConfiguration;
4 | import org.springframework.context.annotation.ComponentScan;
5 |
6 | @SpringBootConfiguration
7 | @ComponentScan
8 | public interface IncludeConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfig.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import me.chanjar.annotation.testconfig.Foo;
4 | import org.springframework.boot.test.context.TestConfiguration;
5 | import org.springframework.context.annotation.Bean;
6 |
7 | @TestConfiguration
8 | public class TestConfig {
9 |
10 | @Bean
11 | public Foo foo() {
12 | return new Foo("from test config");
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigExclude_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
6 | import org.testng.annotations.Test;
7 |
8 | import static org.testng.Assert.assertNull;
9 |
10 | @SpringBootTest(classes = ExcludeConfig1.class)
11 | public class TestConfigExclude_1_Test extends AbstractTestNGSpringContextTests {
12 |
13 | @Autowired(required = false)
14 | private TestConfig testConfig;
15 |
16 | @Test
17 | public void test() throws Exception {
18 | assertNull(testConfig);
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigExclude_2_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
6 | import org.testng.annotations.Test;
7 |
8 | import static org.testng.Assert.assertNull;
9 |
10 | @SpringBootTest(classes = ExcludeConfig2.class)
11 | public class TestConfigExclude_2_Test extends AbstractTestNGSpringContextTests {
12 |
13 | @Autowired(required = false)
14 | private TestConfig testConfig;
15 |
16 | @Test
17 | public void testPlusCount() throws Exception {
18 | assertNull(testConfig);
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigIncludedTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testconfig.ex3;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
6 | import org.testng.annotations.Test;
7 |
8 | import static org.testng.Assert.assertNotNull;
9 |
10 | @SpringBootTest(classes = IncludeConfig.class)
11 | public class TestConfigIncludedTest extends AbstractTestNGSpringContextTests {
12 |
13 | @Autowired(required = false)
14 | private TestConfig testConfig;
15 |
16 | @Test
17 | public void testPlusCount() throws Exception {
18 | assertNotNull(testConfig);
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testps/ex1/PropertySourceConfig.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testps.ex1;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.context.annotation.PropertySource;
5 |
6 | @Configuration
7 | @PropertySource("classpath:me/chanjar/annotation/testps/ex1/property-source.properties")
8 | public class PropertySourceConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testps/ex1/TestPropertyTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testps.ex1;
2 |
3 | import org.springframework.context.EnvironmentAware;
4 | import org.springframework.core.env.ConfigurableEnvironment;
5 | import org.springframework.core.env.Environment;
6 | import org.springframework.test.context.ContextConfiguration;
7 | import org.springframework.test.context.TestPropertySource;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.testng.annotations.Test;
10 |
11 | import java.util.Map;
12 |
13 | import static java.util.stream.Collectors.toList;
14 | import static org.testng.Assert.assertEquals;
15 |
16 | @ContextConfiguration(classes = PropertySourceConfig.class)
17 | @TestPropertySource(
18 | properties = { "foo=xyz", "bar=uvw", "PATH=aaa", "java.runtime.name=bbb" },
19 | locations = "classpath:me/chanjar/annotation/testps/ex1/test-property-source.properties"
20 | )
21 | public class TestPropertyTest extends AbstractTestNGSpringContextTests implements EnvironmentAware {
22 |
23 | private Environment environment;
24 |
25 | @Override
26 | public void setEnvironment(Environment environment) {
27 | this.environment = environment;
28 | Map systemEnvironment = ((ConfigurableEnvironment) environment).getSystemEnvironment();
29 | System.out.println("=== System Environment ===");
30 | System.out.println(getMapString(systemEnvironment));
31 | System.out.println();
32 |
33 | System.out.println("=== Java System Properties ===");
34 | Map systemProperties = ((ConfigurableEnvironment) environment).getSystemProperties();
35 | System.out.println(getMapString(systemProperties));
36 | }
37 |
38 | @Test
39 | public void testOverridePropertySource() {
40 | assertEquals(environment.getProperty("foo"), "xyz");
41 | }
42 |
43 | @Test
44 | public void testOverrideSystemEnvironment() {
45 | assertEquals(environment.getProperty("PATH"), "aaa");
46 | }
47 |
48 | @Test
49 | public void testOverrideJavaSystemProperties() {
50 | assertEquals(environment.getProperty("java.runtime.name"), "bbb");
51 | }
52 |
53 | @Test
54 | public void testInlineTestPropertyOverrideResourceLocationTestProperty() {
55 | assertEquals(environment.getProperty("bar"), "uvw");
56 | }
57 |
58 | private String getMapString(Map map) {
59 | return String.join("\n",
60 | map.keySet().stream().map(k -> k + "=" + map.get(k)).collect(toList())
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/annotation/src/test/java/me/chanjar/annotation/testps/ex2/TestPropertyTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.annotation.testps.ex2;
2 |
3 | import me.chanjar.annotation.testps.ex1.PropertySourceConfig;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 | import org.springframework.context.EnvironmentAware;
6 | import org.springframework.core.env.ConfigurableEnvironment;
7 | import org.springframework.core.env.Environment;
8 | import org.springframework.test.context.TestPropertySource;
9 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
10 | import org.testng.annotations.Test;
11 |
12 | import java.util.Map;
13 |
14 | import static java.util.stream.Collectors.toList;
15 | import static org.testng.Assert.assertEquals;
16 |
17 | @SpringBootTest(classes = PropertySourceConfig.class)
18 | @TestPropertySource(
19 | properties = { "foo=xyz", "bar=uvw", "PATH=aaa", "java.runtime.name=bbb" },
20 | locations = "classpath:me/chanjar/annotation/testps/ex1/test-property-source.properties"
21 | )
22 | public class TestPropertyTest extends AbstractTestNGSpringContextTests implements EnvironmentAware {
23 |
24 | private Environment environment;
25 |
26 | @Override
27 | public void setEnvironment(Environment environment) {
28 | this.environment = environment;
29 | Map systemEnvironment = ((ConfigurableEnvironment) environment).getSystemEnvironment();
30 | System.out.println("=== System Environment ===");
31 | System.out.println(getMapString(systemEnvironment));
32 | System.out.println();
33 |
34 | System.out.println("=== Java System Properties ===");
35 | Map systemProperties = ((ConfigurableEnvironment) environment).getSystemProperties();
36 | System.out.println(getMapString(systemProperties));
37 | }
38 |
39 | @Test
40 | public void testOverridePropertySource() {
41 | assertEquals(environment.getProperty("foo"), "xyz");
42 | }
43 |
44 | @Test
45 | public void testOverrideSystemEnvironment() {
46 | assertEquals(environment.getProperty("PATH"), "aaa");
47 | }
48 |
49 | @Test
50 | public void testOverrideJavaSystemProperties() {
51 | assertEquals(environment.getProperty("java.runtime.name"), "bbb");
52 | }
53 |
54 | @Test
55 | public void testInlineTestPropertyOverrideResourceLocationTestProperty() {
56 | assertEquals(environment.getProperty("bar"), "uvw");
57 | }
58 |
59 | private String getMapString(Map map) {
60 | return String.join("\n",
61 | map.keySet().stream().map(k -> k + "=" + map.get(k)).collect(toList())
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/annotation/src/test/resources/me/chanjar/annotation/jsontest/ex1/expected.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Honda",
3 | "age": 12
4 | }
5 |
--------------------------------------------------------------------------------
/annotation/src/test/resources/me/chanjar/annotation/testps/ex1/property-source.properties:
--------------------------------------------------------------------------------
1 | foo=abc
2 |
--------------------------------------------------------------------------------
/annotation/src/test/resources/me/chanjar/annotation/testps/ex1/test-property-source.properties:
--------------------------------------------------------------------------------
1 | bar=def
2 |
--------------------------------------------------------------------------------
/aop/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-aop
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-aop
26 |
27 |
28 |
29 | org.slf4j
30 | slf4j-api
31 |
32 |
33 |
34 | ch.qos.logback
35 | logback-classic
36 |
37 |
38 |
39 |
40 |
41 | org.testng
42 | testng
43 | test
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-test
49 | test
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | org.apache.maven.plugins
58 | maven-jar-plugin
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/aop/src/main/java/me/chanjar/aop/aspect/FooAspect.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.aspect;
2 |
3 | import org.aspectj.lang.ProceedingJoinPoint;
4 | import org.aspectj.lang.annotation.Around;
5 | import org.aspectj.lang.annotation.Aspect;
6 | import org.aspectj.lang.annotation.Pointcut;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Component
10 | @Aspect
11 | public class FooAspect {
12 |
13 | @Pointcut("execution(* me.chanjar.aop.service.FooServiceImpl.incrementAndGet())")
14 | public void pointcut() {
15 | }
16 |
17 | @Around("pointcut()")
18 | public int changeIncrementAndGet(ProceedingJoinPoint pjp) {
19 | return 0;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/aop/src/main/java/me/chanjar/aop/config/AopConfig.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
6 |
7 | @Configuration
8 | @EnableAspectJAutoProxy(proxyTargetClass = true)
9 | @ComponentScan("me.chanjar.aop")
10 | public class AopConfig {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/aop/src/main/java/me/chanjar/aop/service/FooService.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.service;
2 |
3 | public interface FooService {
4 |
5 | int incrementAndGet();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/aop/src/main/java/me/chanjar/aop/service/FooServiceImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.service;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | @Component
6 | public class FooServiceImpl implements FooService {
7 |
8 | private int count;
9 |
10 | @Override
11 | public int incrementAndGet() {
12 | count++;
13 | return count;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/aop/src/test/java/me/chanjar/aop/ex1/SpringAop_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.ex1;
2 |
3 | import me.chanjar.aop.config.AopConfig;
4 | import me.chanjar.aop.service.FooService;
5 | import me.chanjar.aop.service.FooServiceImpl;
6 | import org.springframework.aop.framework.AopProxyUtils;
7 | import org.springframework.aop.support.AopUtils;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
11 | import org.springframework.test.util.AopTestUtils;
12 | import org.testng.annotations.Test;
13 |
14 | import static org.testng.Assert.*;
15 |
16 | @ContextConfiguration(classes = { SpringAop_1_Test.class, AopConfig.class })
17 | public class SpringAop_1_Test extends AbstractTestNGSpringContextTests {
18 |
19 | @Autowired
20 | private FooService fooService;
21 |
22 | @Test
23 | public void testFooService() {
24 |
25 | assertNotEquals(fooService.getClass(), FooServiceImpl.class);
26 |
27 | assertTrue(AopUtils.isAopProxy(fooService));
28 | assertTrue(AopUtils.isCglibProxy(fooService));
29 |
30 | assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class);
31 |
32 | assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class);
33 | assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
34 |
35 | assertEquals(fooService.incrementAndGet(), 0);
36 | assertEquals(fooService.incrementAndGet(), 0);
37 |
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/aop/src/test/java/me/chanjar/aop/ex2/SpringAop_2_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.ex2;
2 |
3 | import me.chanjar.aop.aspect.FooAspect;
4 | import me.chanjar.aop.config.AopConfig;
5 | import me.chanjar.aop.service.FooService;
6 | import me.chanjar.aop.service.FooServiceImpl;
7 | import org.springframework.aop.framework.AopProxyUtils;
8 | import org.springframework.aop.support.AopUtils;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
11 | import org.springframework.boot.test.mock.mockito.SpyBean;
12 | import org.springframework.test.context.ContextConfiguration;
13 | import org.springframework.test.context.TestExecutionListeners;
14 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
15 | import org.springframework.test.util.AopTestUtils;
16 | import org.testng.annotations.Test;
17 |
18 | import static org.mockito.Matchers.any;
19 | import static org.mockito.Mockito.times;
20 | import static org.mockito.Mockito.verify;
21 | import static org.testng.Assert.assertEquals;
22 | import static org.testng.Assert.assertNotEquals;
23 | import static org.testng.Assert.assertTrue;
24 |
25 | @ContextConfiguration(classes = { SpringAop_2_Test.class, AopConfig.class })
26 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
27 | public class SpringAop_2_Test extends AbstractTestNGSpringContextTests {
28 |
29 | @SpyBean
30 | private FooAspect fooAspect;
31 |
32 | @Autowired
33 | private FooService fooService;
34 |
35 | @Test
36 | public void testFooService() {
37 |
38 | assertNotEquals(fooService.getClass(), FooServiceImpl.class);
39 |
40 | assertTrue(AopUtils.isAopProxy(fooService));
41 | assertTrue(AopUtils.isCglibProxy(fooService));
42 |
43 | assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class);
44 |
45 | assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class);
46 | assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
47 |
48 | assertEquals(fooService.incrementAndGet(), 0);
49 | assertEquals(fooService.incrementAndGet(), 0);
50 |
51 | verify(fooAspect, times(2)).changeIncrementAndGet(any());
52 |
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/aop/src/test/java/me/chanjar/aop/ex3/SpringBootAopTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.aop.ex3;
2 |
3 | import me.chanjar.aop.aspect.FooAspect;
4 | import me.chanjar.aop.config.AopConfig;
5 | import me.chanjar.aop.service.FooService;
6 | import me.chanjar.aop.service.FooServiceImpl;
7 | import org.springframework.aop.framework.AopProxyUtils;
8 | import org.springframework.aop.support.AopUtils;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
12 | import org.springframework.boot.test.mock.mockito.SpyBean;
13 | import org.springframework.test.context.TestExecutionListeners;
14 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
15 | import org.springframework.test.util.AopTestUtils;
16 | import org.testng.annotations.Test;
17 |
18 | import static org.mockito.Matchers.any;
19 | import static org.mockito.Mockito.times;
20 | import static org.mockito.Mockito.verify;
21 | import static org.testng.Assert.*;
22 |
23 | @SpringBootTest(classes = { SpringBootAopTest.class, AopConfig.class })
24 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
25 | public class SpringBootAopTest extends AbstractTestNGSpringContextTests {
26 |
27 | @SpyBean
28 | private FooAspect fooAspect;
29 |
30 | @Autowired
31 | private FooService fooService;
32 |
33 | @Test
34 | public void testFooService() {
35 |
36 | assertNotEquals(fooService.getClass(), FooServiceImpl.class);
37 |
38 | assertTrue(AopUtils.isAopProxy(fooService));
39 | assertTrue(AopUtils.isCglibProxy(fooService));
40 |
41 | assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class);
42 |
43 | assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class);
44 | assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
45 |
46 | assertEquals(fooService.incrementAndGet(), 0);
47 | assertEquals(fooService.incrementAndGet(), 0);
48 |
49 | verify(fooAspect, times(2)).changeIncrementAndGet(any());
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/appendix_i.md:
--------------------------------------------------------------------------------
1 | # 附录I Spring Mock Objects
2 |
3 | Spring提供的[Mock Objects][doc-spring-mock-objects]有以下这些:
4 |
5 | ## package org.springframework.mock.env
6 |
7 | 1. MockEnvironment
8 | 1. MockPropertySource
9 |
10 | ## package org.springframework.mock.jndi
11 |
12 | 1. SimpleNamingContext
13 | 1. ExpectedLookupTemplate
14 | 1. SimpleNamingContextBuilder
15 |
16 | ## package org.springframework.mock.web
17 |
18 | 1. DelegatingServletInputStream
19 | 1. DelegatingServletOutputStream
20 | 1. HeaderValueHolder
21 | 1. MockAsyncContext
22 | 1. MockBodyContent
23 | 1. MockExpressionEvaluator
24 | 1. MockFilterChain
25 | 1. MockFilterConfig
26 | 1. MockHttpServletRequest
27 | 1. MockHttpServletResponse
28 | 1. MockHttpSession
29 | 1. MockJspWriter
30 | 1. MockMultipartFile
31 | 1. MockMultipartHttpServletRequest
32 | 1. MockPageContext
33 | 1. MockRequestDispatcher
34 | 1. MockServletConfig
35 | 1. MockServletContext
36 | 1. MockSessionCookieConfig
37 | 1. PassThroughFilterChain
38 |
39 | [doc-spring-mock-objects]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/unit-testing.html#mock-objects
40 |
--------------------------------------------------------------------------------
/appendix_ii.md:
--------------------------------------------------------------------------------
1 | # 附录II Spring Test Utils
2 |
3 | Spring Boot提供的[Unit Test Utils][spring-test-utils]有以下这些:
4 |
5 | 1. AopTestUtils
6 | 1. AssertionErrors
7 | 1. JsonExpectationsHelper
8 | 1. JsonPathExpectationsHelper
9 | 1. MetaAnnotationUtils
10 | 1. ReflectionTestUtils
11 | 1. XmlExpectationsHelper
12 | 1. XpathExpectationsHelper
13 | 1. ModelAndViewAssert
14 | 1. JdbcTestUtils
15 | 1. BeanFactoryAnnotationUtils,用它getBeanByQualifier特别有用
16 |
17 | Spring Boot提供的[Unit Test Utils][spring-boot-test-utils]有以下这些:
18 |
19 | 1. ConfigFileApplicationContextInitializer
20 | 1. EnvironmentTestUtils
21 | 1. OutputCapture
22 | 1. TestRestTemplate
23 |
24 | [spring-test-utils]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/unit-testing.html#unit-testing-support-classes
25 | [spring-boot-test-utils]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-test-utilities
--------------------------------------------------------------------------------
/basic/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-basic
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-jdbc
26 |
27 |
28 |
29 | com.h2database
30 | h2
31 |
32 |
33 |
34 | org.slf4j
35 | slf4j-api
36 |
37 |
38 |
39 | ch.qos.logback
40 | logback-classic
41 |
42 |
43 |
44 |
45 | org.testng
46 | testng
47 | test
48 |
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-test
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | org.apache.maven.plugins
62 | maven-jar-plugin
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/basic/src/main/java/me/chanjar/basic/service/FooService.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.service;
2 |
3 | public interface FooService {
4 |
5 | void plusCount();
6 |
7 | int getCount();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/basic/src/main/java/me/chanjar/basic/service/FooServiceImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.service;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | @Component
6 | public class FooServiceImpl implements FooService {
7 |
8 | private int count = 0;
9 |
10 | @Override
11 | public void plusCount() {
12 | this.count++;
13 | }
14 |
15 | @Override
16 | public int getCount() {
17 | return count;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/spring/ex1/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.spring.ex1;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import me.chanjar.basic.service.FooServiceImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.test.context.ContextConfiguration;
7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.testng.Assert.assertEquals;
11 |
12 | @ContextConfiguration(classes = FooServiceImpl.class)
13 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
14 |
15 | @Autowired
16 | private FooService foo;
17 |
18 | @Test
19 | public void testPlusCount() throws Exception {
20 | assertEquals(foo.getCount(), 0);
21 |
22 | foo.plusCount();
23 | assertEquals(foo.getCount(), 1);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/spring/ex2/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.spring.ex2;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import me.chanjar.basic.service.FooServiceImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.context.annotation.Import;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
10 | import org.testng.annotations.Test;
11 |
12 | import static org.testng.Assert.assertEquals;
13 |
14 | @ContextConfiguration
15 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
16 |
17 | @Autowired
18 | private FooService foo;
19 |
20 | @Test
21 | public void testPlusCount() throws Exception {
22 | assertEquals(foo.getCount(), 0);
23 |
24 | foo.plusCount();
25 | assertEquals(foo.getCount(), 1);
26 | }
27 |
28 | @Configuration
29 | @Import(FooServiceImpl.class)
30 | static class Config {
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/spring/ex3/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.spring.ex3;
2 |
3 | import me.chanjar.basic.service.FooServiceImpl;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.Import;
6 |
7 | @Configuration
8 | @Import(FooServiceImpl.class)
9 | public class Config {
10 | }
11 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/spring/ex3/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.spring.ex3;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.test.context.ContextConfiguration;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | @ContextConfiguration(classes = Config.class)
12 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Autowired
15 | private FooService foo;
16 |
17 | @Test
18 | public void testPlusCount() throws Exception {
19 | assertEquals(foo.getCount(), 0);
20 |
21 | foo.plusCount();
22 | assertEquals(foo.getCount(), 1);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex1/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex1;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import me.chanjar.basic.service.FooServiceImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.testng.Assert.assertEquals;
11 |
12 | @SpringBootTest(classes = FooServiceImpl.class)
13 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
14 |
15 | @Autowired
16 | private FooService foo;
17 |
18 | @Test
19 | public void testPlusCount() throws Exception {
20 | assertEquals(foo.getCount(), 0);
21 |
22 | foo.plusCount();
23 | assertEquals(foo.getCount(), 1);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex2/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex2;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import me.chanjar.basic.service.FooServiceImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.context.annotation.Import;
9 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
10 | import org.testng.annotations.Test;
11 |
12 | import static org.testng.Assert.assertEquals;
13 |
14 | @SpringBootTest
15 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
16 |
17 | @Autowired
18 | private FooService foo;
19 |
20 | @Test
21 | public void testPlusCount() throws Exception {
22 | assertEquals(foo.getCount(), 0);
23 |
24 | foo.plusCount();
25 | assertEquals(foo.getCount(), 1);
26 | }
27 |
28 | @Configuration
29 | @Import(FooServiceImpl.class)
30 | static class Config {
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex3/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex3;
2 |
3 | import me.chanjar.basic.service.FooServiceImpl;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.Import;
6 |
7 | @Configuration
8 | @Import(FooServiceImpl.class)
9 | public class Config {
10 | }
11 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex3/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex3;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | @SpringBootTest(classes = Config.class)
12 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Autowired
15 | private FooService foo;
16 |
17 | @Test
18 | public void testPlusCount() throws Exception {
19 | assertEquals(foo.getCount(), 0);
20 |
21 | foo.plusCount();
22 | assertEquals(foo.getCount(), 1);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex4/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex4;
2 |
3 | import me.chanjar.basic.service.FooServiceImpl;
4 | import org.springframework.boot.SpringBootConfiguration;
5 | import org.springframework.context.annotation.Import;
6 |
7 | @SpringBootConfiguration
8 | @Import(FooServiceImpl.class)
9 | public class Config {
10 | }
11 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex4/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex4;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | @SpringBootTest
12 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Autowired
15 | private FooService foo;
16 |
17 | @Test
18 | public void testPlusCount() throws Exception {
19 | assertEquals(foo.getCount(), 0);
20 |
21 | foo.plusCount();
22 | assertEquals(foo.getCount(), 1);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex5/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex5;
2 |
3 | import org.springframework.boot.SpringBootConfiguration;
4 | import org.springframework.context.annotation.ComponentScan;
5 |
6 | @SpringBootConfiguration
7 | @ComponentScan(basePackages = "me.chanjar.basic.service")
8 | public class Config {
9 | }
10 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex5/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex5;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | @SpringBootTest
12 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Autowired
15 | private FooService foo;
16 |
17 | @Test
18 | public void testPlusCount() throws Exception {
19 | assertEquals(foo.getCount(), 0);
20 |
21 | foo.plusCount();
22 | assertEquals(foo.getCount(), 1);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex6/Config.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex6;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | @SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
6 | public class Config {
7 | }
8 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/springboot/ex6/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.springboot.ex6;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | @SpringBootTest
12 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
13 |
14 | @Autowired
15 | private FooService foo;
16 |
17 | @Test
18 | public void testPlusCount() throws Exception {
19 | assertEquals(foo.getCount(), 0);
20 |
21 | foo.plusCount();
22 | assertEquals(foo.getCount(), 1);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/basic/src/test/java/me/chanjar/basic/testng/ex1/FooServiceImplTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.basic.testng.ex1;
2 |
3 | import me.chanjar.basic.service.FooService;
4 | import me.chanjar.basic.service.FooServiceImpl;
5 | import org.testng.annotations.Test;
6 |
7 | import static org.testng.Assert.assertEquals;
8 |
9 | public class FooServiceImplTest {
10 |
11 | @Test
12 | public void testPlusCount() {
13 | FooService foo = new FooServiceImpl();
14 | assertEquals(foo.getCount(), 0);
15 |
16 | foo.plusCount();
17 | assertEquals(foo.getCount(), 1);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/chapter_0_concept.md:
--------------------------------------------------------------------------------
1 | # Chapter 0: 基本概念
2 |
3 | 在了解学习本项目提供的例子之前,先了解一下什么是单元测试(Unit Testing,简称UT)和集成测试(Integration Testing,简称IT)。
4 |
5 | 如果你之前没有深究过这两个概念,那么你可能会得出如下错误的答案:
6 |
7 | 错误答案1:
8 |
9 | > 单元测试就是对一个方法进行测试的测试
10 |
11 | 听上去很像那么回事儿,对吧?单元测试,就是测一个逻辑单元,所以就测一个方法就是单元测试,听上去很有道理是不是?但是,那么测试两个方法(这两个方法互相关联)的话叫什么呢?
12 |
13 | 错误答案2:
14 |
15 | > 集成测试是把几个方法或者几个类放在一起测试
16 |
17 | 既然前面单元测试只测一个方法,那么几个方法放在一起测就是集成测试,听上去挺有道理的。那么是不是只要测一个以上的方法就是集成测试呢?
18 |
19 | 错误答案3:
20 |
21 | > 集成测试就是和其他系统联合调试做的测试
22 |
23 | 听上去有点像SOA或者现在流行的微服务是吧。做这种测试的时候必须得各个开发团队紧密配合,一个不小心就会测试失败,然后就是各种返工,总之难度和火箭发射有的一拼。
24 |
25 | 那么正确答案是什么?其实这两个概念的解释比较冗长这里就不细讲了,只需记住UT和IT具备以下特征:
26 |
27 | 1. UT和IT必须是自动化的。
28 | 1. UT只专注于整个系统里的某一小部分,粒度没有规定,一般都比较小可以到方法级别。比如某个字符串串接方法。
29 | 1. UT不需要连接外部系统,在内存里跑跑就行了。
30 | 1. IT需要连接外部系统,比如连接数据库做CRUD测试。
31 | 1. 测试环境和生产环境是隔离的。
32 | 1. 能做UT的就不要做IT。
33 |
34 | 参考链接:
35 |
36 | * [Martin Fowler - Unit Test](https://martinfowler.com/bliki/UnitTest.html)
37 | * [Wikipedia - Unit Testing](https://en.wikipedia.org/wiki/Unit_testing)
38 | * [Wikipedia - Integration Testing](https://en.wikipedia.org/wiki/Integration_testing)
39 |
--------------------------------------------------------------------------------
/chapter_1_intro.md:
--------------------------------------------------------------------------------
1 | # Chapter 1: 基本用法 - 引言
2 |
3 | 本项目所有的项目均采用Maven的标准目录结构:
4 |
5 | * `src/main/java`,程序java文件目录
6 | * `src/main/resource`,程序资源文件目录
7 | * `src/test/java`,测试代码目录
8 | * `src/test/resources`,测试资源文件目录
9 |
10 | 并且所有Maven项目都可以使用`mvn clean test`方式跑单元测试,特别需要注意,只有文件名是`*Test.java`才会被执行,一定要注意这一点哦。
11 |
12 | ## 参考文档
13 |
14 | * [Maven Standard Directory Layout][doc-maven-standard-dir-layout]
15 |
16 | [doc-maven-standard-dir-layout]: https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
17 |
--------------------------------------------------------------------------------
/chapter_1_s1_testng.md:
--------------------------------------------------------------------------------
1 | # Chapter 1: 基本用法 - 认识TestNG
2 |
3 | 先认识一下TestNG,这里有一个[FooServiceImpl][src-FooServiceImpl],里面有两个方法,一个是给计数器+1,一个是获取当前计数器的值:
4 |
5 | ```java
6 | @Component
7 | public class FooServiceImpl implements FooService {
8 |
9 | private int count = 0;
10 |
11 | @Override
12 | public void plusCount() {
13 | this.count++;
14 | }
15 |
16 | @Override
17 | public int getCount() {
18 | return count;
19 | }
20 |
21 | }
22 | ```
23 |
24 | 然后我们针对它有一个[FooServiceImplTest][src-ex1-FooServiceImplTest]作为UT:
25 |
26 | ```java
27 | public class FooServiceImplTest {
28 |
29 | @Test
30 | public void testPlusCount() {
31 | FooService foo = new FooServiceImpl();
32 | assertEquals(foo.getCount(), 0);
33 |
34 | foo.plusCount();
35 | assertEquals(foo.getCount(), 1);
36 | }
37 |
38 | }
39 | ```
40 |
41 | 注意看代码里的`assertEquals(...)`,我们利用它来判断`Foo.getCount`方法是否按照预期执行。所以,所谓的测试其实就是给定输入、执行一些方法,assert结果是否符合预期的过程。
42 |
43 | ## 参考文档
44 |
45 | * [TestNG documentation][doc-testng-doc]
46 |
47 | [doc-testng-doc]: http://testng.org/doc/documentation-main.html
48 | [src-FooServiceImpl]: basic/src/main/java/me/chanjar/basic/service/FooServiceImpl.java
49 | [src-ex1-FooServiceImplTest]: basic/src/test/java/me/chanjar/basic/testng/ex1/FooServiceImplTest.java
50 |
51 |
--------------------------------------------------------------------------------
/chapter_1_s2_spring_testing.md:
--------------------------------------------------------------------------------
1 | # Chapter 1: 基本用法 - 使用Spring Testing工具
2 |
3 | 既然我们现在开发的是一个Spring项目,那么肯定会用到Spring Framework的各种特性,这些特性实在是太好用了,它能够大大提高我们的开发效率。那么自然而然,你会想在测试代码里也能够利用Spring Framework提供的特性,来提高测试代码的开发效率。这部分我们会讲如何使用Spring提供的测试工具来做测试。
4 |
5 | ## 例子1
6 |
7 | 源代码见[FooServiceImplTest][src-ex1-FooServiceImplTest]:
8 |
9 | ```java
10 | @ContextConfiguration(classes = FooServiceImpl.class)
11 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
12 |
13 | @Autowired
14 | private FooService foo;
15 |
16 | @Test
17 | public void testPlusCount() throws Exception {
18 | assertEquals(foo.getCount(), 0);
19 |
20 | foo.plusCount();
21 | assertEquals(foo.getCount(), 1);
22 | }
23 |
24 | }
25 | ```
26 |
27 | 在上面的源代码里我们要注意三点:
28 |
29 | 1. 测试类继承了[AbstractTestNGSpringContextTests][javadoc-AbstractTestNGSpringContextTests],如果不这么做测试类是无法启动Spring容器的
30 | 1. 使用了[@ContextConfiguration][javadoc-ContextConfiguration]来加载被测试的Bean:`FooServiceImpl`
31 | 1. `FooServiceImpl`是`@Component`
32 |
33 | 以上三点缺一不可。
34 |
35 | ## 例子2
36 |
37 | 在这个例子里,我们将`@Configuration`作为nested static class放在测试类里,根据[@ContextConfiguration][doc-spring-ContextConfiguration]的文档,它会在默认情况下查找测试类的nested static @Configuration class,用它来导入Bean。
38 |
39 | 源代码见[FooServiceImplTest][src-ex2-FooServiceImplTest]:
40 |
41 |
42 | ```java
43 | @ContextConfiguration
44 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
45 |
46 | @Autowired
47 | private FooService foo;
48 |
49 | @Test
50 | public void testPlusCount() throws Exception {
51 | assertEquals(foo.getCount(), 0);
52 |
53 | foo.plusCount();
54 | assertEquals(foo.getCount(), 1);
55 | }
56 |
57 | @Configuration
58 | @Import(FooServiceImpl.class)
59 | static class Config {
60 | }
61 |
62 | }
63 | ```
64 |
65 |
66 | ## 例子3
67 |
68 | 在这个例子里,我们将`@Configuration`放到外部,并让[@ContextConfiguration][doc-spring-ContextConfiguration]去加载。
69 |
70 | 源代码见[Config][src-ex3-Config]:
71 |
72 | ```java
73 | @Configuration
74 | @Import(FooServiceImpl.class)
75 | public class Config {
76 | }
77 | ```
78 |
79 | [FooServiceImplTest][src-ex3-FooServiceImplTest]:
80 |
81 | ```java
82 | @ContextConfiguration(classes = Config.class)
83 | public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
84 |
85 | @Autowired
86 | private FooService foo;
87 |
88 | @Test
89 | public void testPlusCount() throws Exception {
90 | assertEquals(foo.getCount(), 0);
91 |
92 | foo.plusCount();
93 | assertEquals(foo.getCount(), 1);
94 | }
95 |
96 | }
97 | ```
98 |
99 | 需要注意的是,如果`@Configuration`是专供某个测试类使用的话,把它放到外部并不是一个好主意,因为它有可能会被`@ComponentScan`扫描到,从而产生一些奇怪的问题。
100 |
101 | ## 参考文档
102 |
103 | * [Spring Framework Testing][doc-spring-framework-testing]
104 | * [Context configuration with annotated classes][doc-spring-ContextConfiguration]
105 |
106 | [doc-spring-ContextConfiguration]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-javaconfig
107 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
108 | [javadoc-AbstractTestNGSpringContextTests]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.html
109 | [src-ex1-FooServiceImplTest]: basic/src/test/java/me/chanjar/basic/spring/ex1/FooServiceImplTest.java
110 | [src-ex2-FooServiceImplTest]: basic/src/test/java/me/chanjar/basic/spring/ex2/FooServiceImplTest.java
111 | [src-ex3-Config]: basic/src/test/java/me/chanjar/basic/spring/ex3/Config.java
112 | [src-ex3-FooServiceImplTest]: basic/src/test/java/me/chanjar/basic/spring/ex3/FooServiceImplTest.java
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/chapter_2_intro.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations
2 |
3 | Spring & Spring Boot Testing工具提供了一些方便测试的Annotation,本章节会对其中的一些做一些讲解。
4 |
--------------------------------------------------------------------------------
/chapter_2_s1_test_property_source.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations - @TestPropertySource
2 |
3 | [@TestPropertySource][javadoc-TestPropertySource]可以用来覆盖掉来自于系统环境变量、Java系统属性、[@PropertySource][javadoc-PropertySource]的属性。
4 |
5 | 同时``@TestPropertySource(properties=...)``优先级高于``@TestPropertySource(locations=...)``。
6 |
7 | 利用它我们可以很方便的在测试代码里微调、模拟配置(比如修改操作系统目录分隔符、数据源等)。
8 |
9 | ## 例子1: 使用Spring Testing工具
10 |
11 | 我们先使用[@PropertySource][javadoc-PropertySource]将一个外部properties文件加载进来,[PropertySourceConfig][src-ex1-PropertySourceConfig]:
12 |
13 | ```java
14 | @Configuration
15 | @PropertySource("classpath:me/chanjar/annotation/testps/ex1/property-source.properties")
16 | public class PropertySourceConfig {
17 | }
18 | ```
19 |
20 | ```
21 | file: property-source.properties
22 | foo=abc
23 | ```
24 |
25 | 然后我们用[@TestPropertySource][javadoc-TestPropertySource]覆盖了这个property:
26 |
27 | ```java
28 | @TestPropertySource(properties = { "foo=xyz" ...
29 | ```
30 |
31 | 最后我们测试了是否覆盖成功(结果是成功的):
32 |
33 | ```java
34 | @Test
35 | public void testOverridePropertySource() {
36 | assertEquals(environment.getProperty("foo"), "xyz");
37 | }
38 | ```
39 |
40 | 同时我们还对@TestPropertySource做了一些其他的测试,具体情况你可以自己观察。为了方便你观察[@TestPropertySource][javadoc-TestPropertySource]对系统环境变量和Java系统属性的覆盖效果,我们在一开始打印出了它们的值。
41 |
42 | 源代码[TestPropertyTest][src-ex1-TestPropertyTest]:
43 |
44 | ```java
45 | @ContextConfiguration(classes = PropertySourceConfig.class)
46 | @TestPropertySource(
47 | properties = { "foo=xyz", "bar=uvw", "PATH=aaa", "java.runtime.name=bbb" },
48 | locations = "classpath:me/chanjar/annotation/testps/ex1/test-property-source.properties"
49 | )
50 | public class TestPropertyTest extends AbstractTestNGSpringContextTests implements EnvironmentAware {
51 |
52 | private Environment environment;
53 |
54 | @Override
55 | public void setEnvironment(Environment environment) {
56 | this.environment = environment;
57 | Map systemEnvironment = ((ConfigurableEnvironment) environment).getSystemEnvironment();
58 | System.out.println("=== System Environment ===");
59 | System.out.println(getMapString(systemEnvironment));
60 | System.out.println();
61 |
62 | System.out.println("=== Java System Properties ===");
63 | Map systemProperties = ((ConfigurableEnvironment) environment).getSystemProperties();
64 | System.out.println(getMapString(systemProperties));
65 | }
66 |
67 | @Test
68 | public void testOverridePropertySource() {
69 | assertEquals(environment.getProperty("foo"), "xyz");
70 | }
71 |
72 | @Test
73 | public void testOverrideSystemEnvironment() {
74 | assertEquals(environment.getProperty("PATH"), "aaa");
75 | }
76 |
77 | @Test
78 | public void testOverrideJavaSystemProperties() {
79 | assertEquals(environment.getProperty("java.runtime.name"), "bbb");
80 | }
81 |
82 | @Test
83 | public void testInlineTestPropertyOverrideResourceLocationTestProperty() {
84 | assertEquals(environment.getProperty("bar"), "uvw");
85 | }
86 |
87 | private String getMapString(Map map) {
88 | return String.join("\n",
89 | map.keySet().stream().map(k -> k + "=" + map.get(k)).collect(toList())
90 | );
91 | }
92 | }
93 | ```
94 |
95 | ## 例子2: 使用Spring Boot Testing工具
96 |
97 | [@TestPropertySource][javadoc-TestPropertySource]也可以和[@SpringBootTest][javadoc-SpringBootTest]一起使用。
98 |
99 | 源代码见[TestPropertyTest][src-ex2-TestPropertyTest]:
100 |
101 | ```java
102 | @SpringBootTest(classes = PropertySourceConfig.class)
103 | @TestPropertySource(
104 | properties = { "foo=xyz", "bar=uvw", "PATH=aaa", "java.runtime.name=bbb" },
105 | locations = "classpath:me/chanjar/annotation/testps/ex1/test-property-source.properties"
106 | )
107 | public class TestPropertyTest extends AbstractTestNGSpringContextTests implements EnvironmentAware {
108 | // ...
109 | }
110 | ```
111 |
112 |
113 |
114 | ## 参考文档
115 |
116 | * [Spring Framework Testing][doc-spring-framework-testing]
117 | * [Spring Boot Testing][doc-spring-boot-testing]
118 | * [Context configuration with test property sources][doc-test-property-source]
119 |
120 | [src-ex1-TestPropertyTest]: annotation/src/test/java/me/chanjar/annotation/testps/ex1/TestPropertyTest.java
121 | [src-ex1-PropertySourceConfig]: annotation/src/test/java/me/chanjar/annotation/testps/ex1/PropertySourceConfig.java
122 | [src-ex2-TestPropertyTest]: annotation/src/test/java/me/chanjar/annotation/testps/ex2/TestPropertyTest.java
123 | [src-ex2-TestPropertyTest]: annotation/src/test/java/me/chanjar/annotation/testps/ex2/TestPropertyTest.java
124 | [javadoc-SpringBootTest]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/context/SpringBootTest.html
125 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
126 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
127 | [javadoc-TestPropertySource]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/test/context/TestPropertySource.html
128 | [javadoc-PropertySource]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html
129 | [javadoc-JsonTest]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/autoconfigure/json/JsonTest.html
130 | [doc-test-property-source]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-property-sources
131 |
--------------------------------------------------------------------------------
/chapter_2_s2_active_profile.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations - [@ActiveProfiles][doc-active-profiles]
2 |
3 | [@ActiveProfiles][doc-active-profiles]可以用来在测试的时候启用某些Profile的Bean。本章节的测试代码使用了下面的这个配置:
4 |
5 | ```java
6 | @Configuration
7 | public class Config {
8 |
9 | @Bean
10 | @Profile("dev")
11 | public Foo fooDev() {
12 | return new Foo("dev");
13 | }
14 |
15 | @Bean
16 | @Profile("product")
17 | public Foo fooProduct() {
18 | return new Foo("product");
19 | }
20 |
21 | @Bean
22 | @Profile("default")
23 | public Foo fooDefault() {
24 | return new Foo("default");
25 | }
26 |
27 | @Bean
28 | public Bar bar() {
29 | return new Bar("no profile");
30 | }
31 |
32 | }
33 | ```
34 |
35 | ## 例子1:不使用ActiveProfiles
36 |
37 | 在没有[@ActiveProfiles][doc-active-profiles]的时候,profile=default和没有设定profile的Bean会被加载到。
38 |
39 | 源代码[ActiveProfileTest][src-ex1-ActiveProfileTest]:
40 |
41 | ```java
42 | @ContextConfiguration(classes = Config.class)
43 | public class ActiveProfileTest extends AbstractTestNGSpringContextTests {
44 |
45 | @Autowired
46 | private Foo foo;
47 |
48 | @Autowired
49 | private Bar bar;
50 |
51 | @Test
52 | public void test() {
53 | assertEquals(foo.getName(), "default");
54 | assertEquals(bar.getName(), "no profile");
55 | }
56 |
57 | }
58 | ```
59 |
60 | ## 例子2:使用ActiveProfiles
61 |
62 | 当使用了[@ActiveProfiles][doc-active-profiles]的时候,profile匹配的和没有设定profile的Bean会被加载到。
63 |
64 | 源代码[ActiveProfileTest][src-ex2-ActiveProfileTest]:
65 |
66 | ```java
67 | @ContextConfiguration(classes = Config.class)
68 | [@ActiveProfiles][doc-active-profiles]("product")
69 | public class ActiveProfileTest extends AbstractTestNGSpringContextTests {
70 |
71 | @Autowired
72 | private Foo foo;
73 |
74 | @Autowired
75 | private Bar bar;
76 |
77 | @Test
78 | public void test() {
79 | assertEquals(foo.getName(), "product");
80 | assertEquals(bar.getName(), "no profile");
81 | }
82 |
83 | }
84 | ```
85 |
86 | ## 总结
87 |
88 | * 在没有[@ActiveProfiles][doc-active-profiles]的时候,profile=default和没有设定profile的Bean会被加载到。
89 | * 当使用了[@ActiveProfiles][doc-active-profiles]的时候,profile匹配的和没有设定profile的Bean会被加载到。
90 |
91 | [@ActiveProfiles][doc-active-profiles]同样也可以和@SpringBootTest配合使用,这里就不举例说明了。
92 |
93 | ## 参考文档
94 |
95 | * [Spring Framework Testing][doc-spring-framework-testing]
96 | * [Spring Boot Testing][doc-spring-boot-testing]
97 |
98 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
99 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
100 | [doc-active-profiles]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#__activeprofiles
101 | [src-ex1-ActiveProfileTest]: annotation/src/test/java/me/chanjar/annotation/activeprofiles/ex1/ActiveProfileTest.java
102 | [src-ex2-ActiveProfileTest]: annotation/src/test/java/me/chanjar/annotation/activeprofiles/ex1/ActiveProfileTest.java
103 |
--------------------------------------------------------------------------------
/chapter_2_s3_json_test.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations - @JsonTest
2 |
3 | [@JsonTest][javadoc-JsonTest]是Spring Boot提供的方便测试JSON序列化反序列化的测试工具,在Spring Boot的[文档][doc-JsonTest]中有一些介绍。
4 |
5 | 需要注意的是[@JsonTest][javadoc-JsonTest]需要Jackson的``ObjectMapper``,事实上如果你的Spring Boot项目添加了`spring-web`的Maven依赖,[JacksonAutoConfiguration][javadoc-JacksonAutoConfiguration]就会自动为你配置一个:
6 |
7 | ```xml
8 |
9 | org.springframework.boot
10 | spring-boot-autoconfigure
11 |
12 |
13 |
14 | org.springframework
15 | spring-web
16 |
17 | ```
18 |
19 | 这里没有提供关于日期时间的例子,关于这个比较复杂,可以看我的另一篇文章:[Spring Boot Jackson对于日期时间类型处理的例子][github-springboot-jackson-datetime-example]。
20 |
21 | ## 例子1:简单例子
22 |
23 | 源代码见[SimpleJsonTest][src-ex1-SimpleJsonTest]:
24 |
25 | ```java
26 | @SpringBootTest(classes = SimpleJsonTest.class)
27 | @JsonTest
28 | public class SimpleJsonTest extends AbstractTestNGSpringContextTests {
29 |
30 | @Autowired
31 | private JacksonTester json;
32 |
33 | @Test
34 | public void testSerialize() throws Exception {
35 | Foo details = new Foo("Honda", 12);
36 | // 使用通包下的json文件测试结果是否正确
37 | assertThat(this.json.write(details)).isEqualToJson("expected.json");
38 | // 或者使用基于JSON path的校验
39 | assertThat(this.json.write(details)).hasJsonPathStringValue("@.name");
40 | assertThat(this.json.write(details)).extractingJsonPathStringValue("@.name").isEqualTo("Honda");
41 | assertThat(this.json.write(details)).hasJsonPathNumberValue("@.age");
42 | assertThat(this.json.write(details)).extractingJsonPathNumberValue("@.age").isEqualTo(12);
43 | }
44 |
45 | @Test
46 | public void testDeserialize() throws Exception {
47 | String content = "{\"name\":\"Ford\",\"age\":13}";
48 | Foo actual = this.json.parseObject(content);
49 | assertThat(actual).isEqualTo(new Foo("Ford", 13));
50 | assertThat(actual.getName()).isEqualTo("Ford");
51 | assertThat(actual.getAge()).isEqualTo(13);
52 |
53 | }
54 |
55 | }
56 | ```
57 |
58 | ## 例子2: 测试@JsonComponent
59 |
60 | [@JsonTest][javadoc-JsonTest]可以用来测试[@JsonComponent][javadoc-JsonComponent]。
61 |
62 | 这个例子里使用了自定义的``@JsonComponent`` [FooJsonComponent][src-ex2-FooJsonComponent]:
63 |
64 | ```java
65 | @JsonComponent
66 | public class FooJsonComponent {
67 |
68 | public static class Serializer extends JsonSerializer {
69 | @Override
70 | public void serialize(Foo value, JsonGenerator gen, SerializerProvider serializers)
71 | throws IOException, JsonProcessingException {
72 | // ...
73 | }
74 |
75 | }
76 |
77 | public static class Deserializer extends JsonDeserializer {
78 |
79 | @Override
80 | public Foo deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
81 | // ...
82 | }
83 |
84 | }
85 |
86 | }
87 |
88 | ```
89 |
90 | 测试代码[JsonComponentJsonTest][src-ex2-JsonComponentJsonTest]:
91 |
92 | ```java
93 | @SpringBootTest(classes = { JsonComponentJacksonTest.class, FooJsonComponent.class })
94 | @JsonTest
95 | public class JsonComponentJacksonTest extends AbstractTestNGSpringContextTests {
96 |
97 | @Autowired
98 | private JacksonTester json;
99 |
100 | @Test
101 | public void testSerialize() throws Exception {
102 | Foo details = new Foo("Honda", 12);
103 | assertThat(this.json.write(details).getJson()).isEqualTo("\"name=Honda,age=12\"");
104 | }
105 |
106 | @Test
107 | public void testDeserialize() throws Exception {
108 | String content = "\"name=Ford,age=13\"";
109 | Foo actual = this.json.parseObject(content);
110 | assertThat(actual).isEqualTo(new Foo("Ford", 13));
111 | assertThat(actual.getName()).isEqualTo("Ford");
112 | assertThat(actual.getAge()).isEqualTo(13);
113 |
114 | }
115 |
116 | }
117 | ```
118 |
119 | ## 例子3: 使用@ContextConfiguration
120 |
121 | 事实上[@JsonTest][javadoc-JsonTest]也可以配合`@ContextConfiguration`一起使用。
122 |
123 | 源代码见[ThinJsonTest][src-ex3-ThinJsonTest]:
124 |
125 | ```java
126 | @JsonTest
127 | @ContextConfiguration(classes = JsonTest.class)
128 | public class ThinJsonTest extends AbstractTestNGSpringContextTests {
129 |
130 | @Autowired
131 | private JacksonTester json;
132 |
133 | @Test
134 | public void testSerialize() throws Exception {
135 | // ...
136 | }
137 |
138 | @Test
139 | public void testDeserialize() throws Exception {
140 | // ...
141 | }
142 |
143 | }
144 |
145 | ```
146 |
147 | ## 参考文档
148 |
149 | * [Spring Framework Testing][doc-spring-framework-testing]
150 | * [Spring Boot Testing][doc-spring-boot-testing]
151 | * [@JsonTest][doc-JsonTest]
152 | * [JsonComponent][javadoc-JsonComponent]
153 | * [JacksonAutoConfiguration][javadoc-JacksonAutoConfiguration]
154 | * [JacksonTester][javadoc-JacksonTester]
155 | * [GsonTester][javadoc-GsonTester]
156 | * [BasicJsonTester][javadoc-BasicJsonTester]
157 |
158 | [src-ex1-SimpleJsonTest]: annotation/src/test/java/me/chanjar/annotation/jsontest/ex1/SimpleJsonTest.java
159 | [src-ex2-JsonComponentJsonTest]: annotation/src/test/java/me/chanjar/annotation/jsontest/ex2/JsonComponentJacksonTest.java
160 | [src-ex2-FooJsonComponent]: annotation/src/test/java/me/chanjar/annotation/jsontest/ex2/FooJsonComponent.java
161 | [src-ex3-ThinJsonTest]: annotation/src/test/java/me/chanjar/annotation/jsontest/ex3/ThinJsonTest.java
162 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
163 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
164 | [doc-JsonTest]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests
165 | [javadoc-JsonTest]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/autoconfigure/json/JsonTest.html
166 | [javadoc-JsonTest]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/autoconfigure/json/JsonTest.html
167 | [javadoc-JacksonTester]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/JacksonTester.html
168 | [javadoc-GsonTester]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/GsonTester.html
169 | [javadoc-BasicJsonTester]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/BasicJsonTester.html
170 | [javadoc-JacksonAutoConfiguration]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.html
171 | [javadoc-JsonComponent]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/jackson/JsonComponent.html
172 | [github-springboot-jackson-datetime-example]: https://github.com/chanjarster/springboot-jackson-datetime-example
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/chapter_2_s4_override_auto_configuration.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations - @OverrideAutoConfiguration
2 |
3 | 在[Chapter 1: 基本用法 - 使用Spring Boot Testing工具][chapter_1_s3_spring_boot_testing.md]里提到:
4 |
5 | > 除了单元测试(不需要初始化ApplicationContext的测试)外,尽量将测试配置和生产配置保持一致。比如如果生产配置里启用了AutoConfiguration,那么测试配置也应该启用。因为只有这样才能够在测试环境下发现生产环境的问题,也避免出现一些因为配置不同导致的奇怪问题。
6 |
7 | 那么当我们想在测试代码里关闭Auto Configuration如何处理?
8 |
9 | 1. 方法1:提供另一套测试配置
10 | 1. 方法2:使用`@OverrideAutoConfiguration`
11 |
12 | 方法1虽然能够很好的解决问题,但是比较麻烦。而方法2则能够不改变原有配置、不提供新的配置的情况下,就能够关闭Auto Configuration。
13 |
14 | 在本章节的例子里,我们自己做了一个Auto Configuration类,[AutoConfigurationEnableLogger][src-AutoConfigurationEnableLogger]:
15 |
16 | ```java
17 | @Configuration
18 | public class AutoConfigurationEnableLogger {
19 |
20 | private static final Logger LOGGER = LoggerFactory.getLogger(AutoConfigurationEnableLogger.class);
21 |
22 | public AutoConfigurationEnableLogger() {
23 | LOGGER.info("Auto Configuration Enabled");
24 | }
25 |
26 | }
27 | ```
28 |
29 | 并且在`META-INF/spring.factories`里注册了它:
30 |
31 | ```
32 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
33 | me.chanjar.annotation.overrideac.AutoConfigurationEnableLogger
34 | ```
35 |
36 | 这样一来,只要Spring Boot启动了Auto Configuration就会打印出日志:
37 |
38 | ```
39 | 2017-08-24 16:44:52.789 INFO 13212 --- [ main] m.c.a.o.AutoConfigurationEnableLogger : Auto Configuration Enabled
40 | ```
41 |
42 | ## 例子1:未关闭Auto Configuration
43 |
44 | 源代码见[BootTest][src-ex1-BootTest]:
45 |
46 | ```java
47 | @SpringBootTest
48 | @SpringBootApplication
49 | public class BootTest extends AbstractTestNGSpringContextTests {
50 |
51 | @Test
52 | public void testName() throws Exception {
53 |
54 | }
55 | }
56 | ```
57 |
58 | 查看输出的日志,会发现Auto Configuration已经启用。
59 |
60 | ## 例子2:关闭Auto Configuration
61 |
62 | 然后我们用[@OverrideAutoConfiguration][javadoc-OverrideAutoConfiguration]关闭了Auto Configuration。
63 |
64 | 源代码见[BootTest][src-ex2-BootTest]:
65 |
66 | ```java
67 | @SpringBootTest
68 | @OverrideAutoConfiguration(enabled = false)
69 | @SpringBootApplication
70 | public class BootTest extends AbstractTestNGSpringContextTests {
71 |
72 | @Test
73 | public void testName() throws Exception {
74 |
75 | }
76 | }
77 | ```
78 |
79 | 再查看输出的日志,就会发现Auto Configuration已经关闭。
80 |
81 |
82 | ## 参考文档
83 |
84 | * [Spring Framework Testing][doc-spring-framework-testing]
85 | * [Spring Boot Testing][doc-spring-boot-testing]
86 | * [Context configuration with test property sources][doc-test-property-source]
87 |
88 | [chapter_1_s3_spring_boot_testing.md]: chapter_1_s3_spring_boot_testing.md
89 | [javadoc-OverrideAutoConfiguration]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/autoconfigure/OverrideAutoConfiguration.html
90 |
91 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
92 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
93 | [src-AutoConfigurationEnableLogger]: annotation/src/main/java/me/chanjar/annotation/overrideac/AutoConfigurationEnableLogger.java
94 | [src-ex1-BootTest]: annotation/src/test/java/me/chanjar/annotation/overrideac/ex1/BootTest.java
95 | [src-ex2-BootTest]: annotation/src/test/java/me/chanjar/annotation/overrideac/ex2/BootTest.java
96 |
--------------------------------------------------------------------------------
/chapter_2_s5_test_configuration.md:
--------------------------------------------------------------------------------
1 | # Chapter 2: Annotations - @TestConfiguration
2 |
3 | [@TestConfiguration][javadoc-test-configuration]是Spring Boot Test提供的一种工具,用它我们可以在一般的@Configuration之外补充测试专门用的Bean或者自定义的配置。
4 |
5 | [@TestConfiguration][javadoc-test-configuration]实际上是一种[@TestComponent][javadoc-test-component],[@TestComponent][javadoc-test-component]是另一种@Component,在语义上用来指定某个Bean是专门用于测试的。
6 |
7 | 需要特别注意,你应该使用一切办法避免在生产代码中自动扫描到[@TestComponent][javadoc-test-component]。
8 | 如果你使用`@SpringBootApplication`启动测试或者生产代码,[@TestComponent][javadoc-test-component]会自动被排除掉,如果不是则需要像`@SpringBootApplication`一样添加`TypeExcludeFilter`:
9 |
10 | ```java
11 | //...
12 | @ComponentScan(excludeFilters = {
13 | @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
14 | // ...})
15 | public @interface SpringBootApplication
16 | ```
17 |
18 | ## 例子1:作为内部类
19 |
20 | [@TestConfiguration][javadoc-test-configuration]和@Configuration不同,它不会阻止@SpringBootTest去查找机制(在[Chapter 1: 基本用法 - 使用Spring Boot Testing工具 - 例子4][chapter_1_s3_spring_boot_testing]提到过),正如[@TestConfiguration][javadoc-test-configuration]的javadoc所说,它只是对既有配置的一个补充。
21 |
22 | 所以我们在测试代码上添加@SpringBootConfiguration,用`@SpringBootTest(classes=...)`或者在同package里添加@SpringBootConfiguration类都是可以的。
23 |
24 | 而且[@TestConfiguration][javadoc-test-configuration]作为内部类的时候它是会被@SpringBootTest扫描掉的,这点和@Configuration一样。
25 |
26 | 测试代码[TestConfigurationTest][src-ex1-TestConfigurationTest]:
27 |
28 | ```java
29 | @SpringBootTest
30 | @SpringBootConfiguration
31 | public class TestConfigurationTest extends AbstractTestNGSpringContextTests {
32 |
33 | @Autowired
34 | private Foo foo;
35 |
36 | @Test
37 | public void testPlusCount() throws Exception {
38 | assertEquals(foo.getName(), "from test config");
39 | }
40 |
41 | @TestConfiguration
42 | public class TestConfig {
43 |
44 | @Bean
45 | public Foo foo() {
46 | return new Foo("from test config");
47 | }
48 |
49 | }
50 | }
51 | ```
52 |
53 |
54 |
55 | ## 例子2:对@Configuration的补充和覆盖
56 |
57 | [@TestConfiguration][javadoc-test-configuration]能够:
58 |
59 | 1. 补充额外的Bean
60 | 1. 覆盖已存在的Bean
61 |
62 | 要特别注意第二点,[@TestConfiguration][javadoc-test-configuration]能够直接覆盖已存在的Bean,这一点正常的@Configuration是做不到的。
63 |
64 | 我们先提供了一个正常的@Configuration([Config][src-ex2-Config]):
65 |
66 | ```java
67 | @Configuration
68 | public class Config {
69 |
70 | @Bean
71 | public Foo foo() {
72 | return new Foo("from config");
73 | }
74 | }
75 | ```
76 |
77 | 又提供了一个@TestConfiguration,在里面覆盖了`foo` Bean,并且提供了`foo2` Bean([TestConfig][src-ex2-TestConfig]):
78 |
79 | ```java
80 | @TestConfiguration
81 | public class TestConfig {
82 |
83 | // 这里不需要@Primary之类的机制,直接就能够覆盖
84 | @Bean
85 | public Foo foo() {
86 | return new Foo("from test config");
87 | }
88 |
89 | @Bean
90 | public Foo foo2() {
91 | return new Foo("from test config2");
92 | }
93 | }
94 | ```
95 |
96 | 测试代码[TestConfigurationTest][src-ex2-TestConfigurationTest]:
97 |
98 | ```java
99 | @SpringBootTest(classes = { Config.class, TestConfig.class })
100 | public class TestConfigurationTest extends AbstractTestNGSpringContextTests {
101 |
102 | @Qualifier("foo")
103 | @Autowired
104 | private Foo foo;
105 |
106 | @Qualifier("foo2")
107 | @Autowired
108 | private Foo foo2;
109 |
110 | @Test
111 | public void testPlusCount() throws Exception {
112 | assertEquals(foo.getName(), "from test config");
113 | assertEquals(foo2.getName(), "from test config2");
114 |
115 | }
116 |
117 | }
118 | ```
119 |
120 | 再查看输出的日志,就会发现Auto Configuration已经关闭。
121 |
122 | ## 例子3:避免@TestConfiguration被扫描到
123 |
124 | 在上面的这个例子里的[TestConfig][src-ex2-TestConfig]是会被@ComponentScan扫描到的,如果要避免被扫描到,在本文开头已经提到过了。
125 |
126 | 先来看一下没有做任何过滤的情形,我们先提供了一个@SpringBootConfiguration([IncludeConfig][src-ex3-IncludeConfig]):
127 |
128 | ```java
129 | @SpringBootConfiguration
130 | @ComponentScan
131 | public interface IncludeConfig {
132 | }
133 | ```
134 |
135 | 然后有个测试代码引用了它([TestConfigIncludedTest][src-ex3-TestConfigIncludedTest]):
136 |
137 | ```java
138 | @SpringBootTest(classes = IncludeConfig.class)
139 | public class TestConfigIncludedTest extends AbstractTestNGSpringContextTests {
140 |
141 | @Autowired(required = false)
142 | private TestConfig testConfig;
143 |
144 | @Test
145 | public void testPlusCount() throws Exception {
146 | assertNotNull(testConfig);
147 |
148 | }
149 |
150 | }
151 | ```
152 |
153 | 从这段代码可以看到`TestConfig`被加载了。
154 |
155 | 现在我们使用TypeExcludeFilter来过滤@TestConfiguration([ExcludeConfig1][src-ex3-ExcludeConfig1]):
156 |
157 | ```java
158 | @SpringBootConfiguration
159 | @ComponentScan(excludeFilters = {
160 | @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)
161 | })
162 | public interface ExcludeConfig1 {
163 | }
164 | ```
165 |
166 | 再来看看结果([TestConfigExclude_1_Test][src-ex3-TestConfigExclude_1_Test]):
167 |
168 | ```java
169 | @SpringBootTest(classes = ExcludeConfig1.class)
170 | public class TestConfigExclude_1_Test extends AbstractTestNGSpringContextTests {
171 |
172 | @Autowired(required = false)
173 | private TestConfig testConfig;
174 |
175 | @Test
176 | public void test() throws Exception {
177 | assertNull(testConfig);
178 |
179 | }
180 |
181 | }
182 | ```
183 |
184 | 还可以用@SpringBootApplication来排除`TestConfig`([ExcludeConfig2][src-ex3-ExcludeConfig2]):
185 |
186 | ```java
187 | @SpringBootApplication
188 | public interface ExcludeConfig2 {
189 | }
190 | ```
191 |
192 | 看看结果([TestConfigExclude_2_Test][src-ex3-TestConfigExclude_2_Test]):
193 |
194 | ```java
195 | @SpringBootTest(classes = ExcludeConfig2.class)
196 | public class TestConfigExclude_2_Test extends AbstractTestNGSpringContextTests {
197 |
198 | @Autowired(required = false)
199 | private TestConfig testConfig;
200 |
201 | @Test
202 | public void testPlusCount() throws Exception {
203 | assertNull(testConfig);
204 |
205 | }
206 |
207 | }
208 | ```
209 |
210 | ## 参考文档
211 |
212 | * [Spring Framework Testing][doc-spring-framework-testing]
213 | * [Spring Boot Testing][doc-spring-boot-testing]
214 | * [Detecting test configuration][doc-spring-boot-detecting-test-configuration]
215 | * [Excluding test configuration][doc-spring-boot-excluding-test-configuration]
216 |
217 | [chapter_1_s3_spring_boot_testing]: chapter_1_s3_spring_boot_testing.md
218 |
219 | [javadoc-test-configuration]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/context/TestConfiguration.html
220 | [javadoc-test-component]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/context/TestComponent.html
221 | [src-ex1-TestConfigurationTest]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex1/TestConfigurationTest.java
222 | [src-ex2-Config]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/Config.java
223 | [src-ex2-TestConfig]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/TestConfig.java
224 | [src-ex2-TestConfigurationTest]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex2/TestConfigurationTest.java
225 | [src-ex3-ExcludeConfig1]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/ExcludeConfig1.java
226 | [src-ex3-ExcludeConfig2]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/ExcludeConfig2.java
227 | [src-ex3-IncludeConfig]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/IncludeConfig.java
228 | [src-ex3-TestConfig]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfig.java
229 | [src-ex3-TestConfigExclude_1_Test]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigExclude_1_Test.java
230 | [src-ex3-TestConfigExclude_2_Test]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigExclude_2_Test.java
231 | [src-ex3-TestConfigIncludedTest]: annotation/src/test/java/me/chanjar/annotation/testconfig/ex3/TestConfigIncludedTest.java
232 |
233 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
234 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
235 | [doc-spring-boot-detecting-test-configuration]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-detecting-config
236 | [doc-spring-boot-excluding-test-configuration]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-excluding-config
237 |
--------------------------------------------------------------------------------
/chapter_3_mockito.md:
--------------------------------------------------------------------------------
1 | # Chapter 3: 使用Mockito
2 |
3 | Mock测试技术能够避免你为了测试一个方法,却需要自行构建整个依赖关系的工作,并且能够让你专注于当前被测试对象的逻辑,而不是其依赖的其他对象的逻辑。
4 |
5 | 举例来说,比如你需要测试`Foo.methodA`,而这个方法依赖了`Bar.methodB`,又传递依赖到了`Zoo.methodC`,于是它们的依赖关系就是`Foo->Bar->Zoo`,所以在测试代码里你必须自行new Bar和Zoo。
6 |
7 | 有人会说:"我直接用Spring的DI机制不就行了吗?"的确,你可以用Spring的DI机制,不过解决不了测试代码耦合度过高的问题:
8 |
9 | 因为Foo方法内部调用了Bar和Zoo的方法,所以你对其做单元测试的时候,必须完全了解Bar和Zoo方法的内部逻辑,并且谨慎的传参和assert结果,一旦Bar和Zoo的代码修改了,你的Foo测试代码很可能就会运行失败。
10 |
11 | 所以这个时候我们需要一种机制,能过让我们在测试Foo的时候不依赖于Bar和Zoo的具体实现,即不关心其内部逻辑,只关注Foo内部的逻辑,从而将Foo的每个逻辑分支都测试到。
12 |
13 | 所以业界就产生了Mock技术,它可以让我们做一个假的Bar(不需要Zoo,因为只有真的Bar才需要Zoo),然后控制这个假的Bar的行为(让它返回什么就返回什么),以此来测试Foo的每个逻辑分支。
14 |
15 | 你肯定会问,这样的测试有意义吗?在真实环境里Foo用的是真的Bar而不是假的Bar,你用假的Bar测试成功能代表真实环境不出问题?
16 |
17 | 其实假Bar代表的是一个行为正确的Bar,用它来测试就能验证"在Bar行为正确的情况下Foo的行为是否正确",而真Bar的行为是否正确会由它自己的测试代码来验证。
18 |
19 | Mock技术的另一个好处是能够让你尽量避免集成测试,比如我们可以Mock一个Repository(数据库操作类),让我们尽量多写单元测试,提高测试代码执行效率。
20 |
21 | `spring-boot-starter-test`依赖了[Mockito][site-mockito],所以我们会在本章里使用Mockito来讲解。
22 |
23 | ## 被测试类
24 |
25 | 先介绍一下接下来要被我们测试的类[Foo][src-Foo]、[Bar][src-Bar]俩兄弟。
26 |
27 | ```java
28 | public interface Foo {
29 |
30 | boolean checkCodeDuplicate(String code);
31 |
32 | }
33 |
34 | public interface Bar {
35 |
36 | Set getAllCodes();
37 |
38 | }
39 |
40 | @Component
41 | public class FooImpl implements Foo {
42 |
43 | private Bar bar;
44 |
45 | @Override
46 | public boolean checkCodeDuplicate(String code) {
47 | return bar.getAllCodes().contains(code);
48 | }
49 |
50 | @Autowired
51 | public void setBar(Bar bar) {
52 | this.bar = bar;
53 | }
54 |
55 | }
56 | ```
57 |
58 |
59 | ## 例子1: 不使用Mock技术
60 |
61 | 源代码[NoMockTest][src-NoMockTest]:
62 |
63 | ```java
64 | public class NoMockTest {
65 |
66 | @Test
67 | public void testCheckCodeDuplicate1() throws Exception {
68 |
69 | FooImpl foo = new FooImpl();
70 | foo.setBar(new Bar() {
71 | @Override
72 | public Set getAllCodes() {
73 | return Collections.singleton("123");
74 | }
75 | });
76 | assertEquals(foo.checkCodeDuplicate("123"), true);
77 |
78 | }
79 |
80 | @Test
81 | public void testCheckCodeDuplicate2() throws Exception {
82 |
83 | FooImpl foo = new FooImpl();
84 | foo.setBar(new FakeBar(Collections.singleton("123")));
85 | assertEquals(foo.checkCodeDuplicate("123"), true);
86 |
87 | }
88 |
89 | public class FakeBar implements Bar {
90 |
91 | private final Set codes;
92 |
93 | public FakeBar(Set codes) {
94 | this.codes = codes;
95 | }
96 |
97 | @Override
98 | public Set getAllCodes() {
99 | return codes;
100 | }
101 |
102 | }
103 |
104 | }
105 | ```
106 |
107 | 这个测试代码里用到了两种方法来做假的Bar:
108 |
109 | 1. 匿名内部类
110 | 1. 做了一个``FakeBar``
111 |
112 | 这两种方式都不是很优雅,看下面使用Mockito的例子。
113 |
114 | ## 例子2:使用Mockito
115 |
116 | 源代码[MockitoTest][src-MockitoTest]:
117 |
118 | ```java
119 | public class MockitoTest {
120 |
121 | @Mock
122 | private Bar bar;
123 |
124 | @InjectMocks
125 | private FooImpl foo;
126 |
127 | @BeforeMethod(alwaysRun = true)
128 | public void initMock() {
129 | MockitoAnnotations.initMocks(this);
130 | }
131 |
132 | @Test
133 | public void testCheckCodeDuplicate() throws Exception {
134 |
135 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
136 | assertEquals(foo.checkCodeDuplicate("123"), true);
137 |
138 | }
139 |
140 | }
141 | ```
142 |
143 | 1. 我们先给了一个Bar的Mock实现:`@Mock private Bar bar;`
144 | 1. 然后又规定了`getAllCodes`方法的返回值:`when(bar.getAllCodes()).thenReturn(Collections.singleton("123"))`。这样就把一个假的Bar定义好了。
145 | 1. 最后利用Mockito把Bar注入到Foo里面,`@InjectMocks private FooImpl foo;`、`MockitoAnnotations.initMocks(this);`
146 |
147 |
148 | ## 例子3:配合Spring Test
149 |
150 | 源代码[Spring_1_Test][src-Spring_1_Test]:
151 |
152 | ```java
153 | @ContextConfiguration(classes = FooImpl.class)
154 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
155 | public class Spring_1_Test extends AbstractTestNGSpringContextTests {
156 |
157 | @MockBean
158 | private Bar bar;
159 |
160 | @Autowired
161 | private Foo foo;
162 |
163 | @Test
164 | public void testCheckCodeDuplicate() throws Exception {
165 |
166 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
167 | assertEquals(foo.checkCodeDuplicate("123"), true);
168 |
169 | }
170 |
171 | }
172 | ```
173 |
174 | 要注意,如果要启用Spring和Mockito,必须添加这么一行:`@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)`。
175 |
176 |
177 | ## 例子4:配合Spring Test(多层依赖)
178 |
179 | 当Bean存在这种依赖关系当时候:`LooImpl -> FooImpl -> Bar`,我们应该怎么测试呢?
180 |
181 | 按照Mock测试的原则,这个时候我们应该mock一个`Foo`对象,把这个注入到`LooImpl`对象里,就像例子3里的一样。
182 |
183 | 不过如果你不想mock `Foo`而是想mock `Bar`的时候,其实做法和前面也差不多,Spring会自动将mock Bar注入到`FooImpl`中,然后将`FooImpl`注入到`LooImpl`中。
184 |
185 | 源代码[Spring_2_Test][src-Spring_2_Test]:
186 |
187 | ```java
188 | @ContextConfiguration(classes = { FooImpl.class, LooImpl.class })
189 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
190 | public class Spring_2_Test extends AbstractTestNGSpringContextTests {
191 |
192 | @MockBean
193 | private Bar bar;
194 |
195 | @Autowired
196 | private Loo loo;
197 |
198 | @Test
199 | public void testCheckCodeDuplicate() throws Exception {
200 |
201 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
202 | assertEquals(loo.checkCodeDuplicate("123"), true);
203 |
204 | }
205 |
206 | }
207 | ```
208 |
209 | 也就是说,得益于Spring Test Framework,我们能够很方便地对依赖关系中任意层级的任意Bean做mock。
210 |
211 | ## 例子5:配合Spring Boot Test
212 |
213 | 源代码[Boot_1_Test][src-Boot_1_Test]:
214 |
215 | ```java
216 | @SpringBoot_1_Test(classes = { FooImpl.class })
217 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
218 | public class Boot_1_Test extends AbstractTestNGSpringContextTests {
219 |
220 | @MockBean
221 | private Bar bar;
222 |
223 | @Autowired
224 | private Foo foo;
225 |
226 | @Test
227 | public void testCheckCodeDuplicate() throws Exception {
228 |
229 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
230 | assertEquals(foo.checkCodeDuplicate("123"), true);
231 |
232 | }
233 |
234 | }
235 | ```
236 |
237 |
238 | ## 参考文档
239 |
240 | * [Spring Framework Testing][doc-spring-framework-testing]
241 | * [Spring Boot Testing][doc-spring-boot-testing]
242 | * [Mockito][site-mockito]
243 |
244 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
245 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
246 | [site-mockito]: http://site.mockito.org
247 | [src-Bar]: mock/src/main/java/me/chanjar/common/Bar.java
248 | [src-Foo]: mock/src/main/java/me/chanjar/common/Foo.java
249 | [src-FooController]: mock/src/main/java/me/chanjar/common/FooController.java
250 | [src-FooImpl]: mock/src/main/java/me/chanjar/common/FooImpl.java
251 | [src-FakeBar]: mock/src/test/java/me/chanjar/no_mock/FakeBar.java
252 | [src-NoMockTest]: mock/src/test/java/me/chanjar/no_mock/NoMockTest.java
253 | [src-Spring_1_Test]: mock/src/test/java/me/chanjar/spring1/Spring_1_Test.java
254 | [src-Spring_2_Test]: mock/src/test/java/me/chanjar/spring2/Spring_2_Test.java
255 | [src-Boot_1_Test]: mock/src/test/java/me/chanjar/springboot1/Boot_1_Test.java
256 |
--------------------------------------------------------------------------------
/chapter_4_s1_basic.md:
--------------------------------------------------------------------------------
1 | # Chapter 4: 测试关系型数据库 - 基本做法
2 |
3 | [Spring Test Framework][doc-spring-framework-testing]提供了对[JDBC的支持][doc-spring-testing-jdbc],能够让我们很方便对关系型数据库做集成测试。
4 |
5 | 同时Spring Boot提供了和[Flyway][site-flyway]的[集成][doc-spring-boot-flyway]支持,能够方便的管理开发过程中产生的SQL文件,配合Spring已经提供的工具能够更方便地在测试之前初始化数据库以及测试之后清空数据库。
6 |
7 | 本章节为了方便起见,本章节使用了H2作为测试数据库。
8 |
9 | 注意:**在真实的开发环境中,集成测试用数据库应该和最终的生产数据库保持一致**,这是因为不同数据库的对于SQL不是完全相互兼容的,如果不注意这一点,很有可能出现集成测试通过,但是上了生产环境却报错的问题。
10 |
11 | 因为是集成测试,所以我们使用了``maven-failsafe-plugin``来跑,它和``maven-surefire-plugin``的差别在于,``maven-failsafe-plugin``只会搜索``*IT.java``来跑测试,而``maven-surefire-plugin``只会搜索``*Test.java``来跑测试。
12 |
13 | 如果想要在maven打包的时候跳过集成测试,只需要``mvn clean install -DskipITs``。
14 |
15 | ## 被测试类
16 |
17 | 先介绍一下被测试的类。
18 |
19 | [Foo.java][src-Foo.java]:
20 |
21 | ```java
22 | public class Foo {
23 |
24 | private String name;
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 | }
34 | ```
35 |
36 | [FooRepositoryImpl.java][src-FooRepositoryImpl.java]:
37 |
38 | ```java
39 | @Repository
40 | public class FooRepositoryImpl implements FooRepository {
41 |
42 | private JdbcTemplate jdbcTemplate;
43 |
44 | @Override
45 | public void save(Foo foo) {
46 | jdbcTemplate.update("INSERT INTO FOO(name) VALUES (?)", foo.getName());
47 | }
48 |
49 | @Override
50 | public void delete(String name) {
51 | jdbcTemplate.update("DELETE FROM FOO WHERE NAME = ?", name);
52 | }
53 |
54 | @Autowired
55 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
56 | this.jdbcTemplate = jdbcTemplate;
57 | }
58 |
59 | }
60 |
61 | ```
62 |
63 | ## 例子1:不使用Spring Testing提供的工具
64 |
65 | [Spring_1_IT_Configuration.java][src-Spring_1_IT_Configuration.java]:
66 |
67 | ```java
68 | @Configuration
69 | @ComponentScan(basePackageClasses = FooRepository.class)
70 | public class Spring_1_IT_Configuration {
71 |
72 | @Bean(destroyMethod = "shutdown")
73 | public DataSource dataSource() {
74 |
75 | return new EmbeddedDatabaseBuilder()
76 | .generateUniqueName(true)
77 | .setType(EmbeddedDatabaseType.H2)
78 | .setScriptEncoding("UTF-8")
79 | .ignoreFailedDrops(true)
80 | .addScript("classpath:me/chanjar/domain/foo-ddl.sql")
81 | .build();
82 | }
83 |
84 | @Bean
85 | public JdbcTemplate jdbcTemplate() {
86 |
87 | return new JdbcTemplate(dataSource());
88 |
89 | }
90 | }
91 | ```
92 |
93 | 在``Spring_1_IT_Configuration``中,我们定义了一个H2的DataSource Bean,并且构建了JdbcTemplate Bean。
94 |
95 | 注意看``addScript("classpath:me/chanjar/domain/foo-ddl.sql")``这句代码,我们让``EmbeddedDatabase``执行[foo-ddl.sql][src-foo-ddl.sql]脚本来建表:
96 |
97 | ```sql
98 | CREATE TABLE FOO (
99 | name VARCHAR2(100)
100 | );
101 | ```
102 |
103 | [Spring_1_IT.java][src-Spring_1_IT.java]:
104 |
105 | ```java
106 | @ContextConfiguration(classes = Spring_1_IT_Configuration.class)
107 | public class Spring_1_IT extends AbstractTestNGSpringContextTests {
108 |
109 | @Autowired
110 | private FooRepository fooRepository;
111 |
112 | @Autowired
113 | private JdbcTemplate jdbcTemplate;
114 |
115 | @Test
116 | public void testSave() {
117 |
118 | Foo foo = new Foo();
119 | foo.setName("Bob");
120 | fooRepository.save(foo);
121 |
122 | assertEquals(
123 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
124 | Integer.valueOf(1)
125 | );
126 |
127 | }
128 |
129 | @Test(dependsOnMethods = "testSave")
130 | public void testDelete() {
131 |
132 | assertEquals(
133 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
134 | Integer.valueOf(1)
135 | );
136 |
137 | Foo foo = new Foo();
138 | foo.setName("Bob");
139 | fooRepository.save(foo);
140 |
141 | fooRepository.delete(foo.getName());
142 | assertEquals(
143 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
144 | Integer.valueOf(0)
145 | );
146 | }
147 |
148 | }
149 | ```
150 |
151 | 在这段测试代码里可以看到,我们分别测试了``FooRepository``的``save``和``delete``方法,并且利用``JdbcTemplate``来验证数据库中的结果。
152 |
153 |
154 | ## 例子2:使用Spring Testing提供的工具
155 |
156 | 在这个例子里,我们会使用[JdbcTestUtils][doc-spring-testing-jdbc]来辅助测试。
157 |
158 | [Spring_2_IT_Configuration.java][src-Spring_2_IT_Configuration.java]:
159 |
160 | ```java
161 | @Configuration
162 | @ComponentScan(basePackageClasses = FooRepository.class)
163 | public class Spring_2_IT_Configuration {
164 |
165 | @Bean
166 | public DataSource dataSource() {
167 |
168 | EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
169 | .generateUniqueName(true)
170 | .setType(EmbeddedDatabaseType.H2)
171 | .setScriptEncoding("UTF-8")
172 | .ignoreFailedDrops(true)
173 | .addScript("classpath:me/chanjar/domain/foo-ddl.sql")
174 | .build();
175 | return db;
176 | }
177 |
178 | @Bean
179 | public JdbcTemplate jdbcTemplate() {
180 |
181 | return new JdbcTemplate(dataSource());
182 |
183 | }
184 |
185 | @Bean
186 | public PlatformTransactionManager transactionManager() {
187 | return new DataSourceTransactionManager(dataSource());
188 | }
189 |
190 | }
191 | ```
192 |
193 | 这里和例子1的区别在于,我们提供了一个``PlatformTransactionManager`` Bean,这是因为在下面的测试代码里的``AbstractTransactionalTestNGSpringContextTests``需要它。
194 |
195 | [Spring_2_IT.java][src-Spring_2_IT.java]:
196 |
197 | ```java
198 | @ContextConfiguration(classes = Spring_2_IT_Configuration.class)
199 | public class Spring_2_IT extends AbstractTransactionalTestNGSpringContextTests {
200 |
201 | @Autowired
202 | private FooRepository fooRepository;
203 |
204 | @Test
205 | public void testSave() {
206 |
207 | Foo foo = new Foo();
208 | foo.setName("Bob");
209 | fooRepository.save(foo);
210 |
211 | assertEquals(countRowsInTable("FOO"), 1);
212 | countRowsInTableWhere("FOO", "name = 'Bob'");
213 | }
214 |
215 | @Test(dependsOnMethods = "testSave")
216 | public void testDelete() {
217 |
218 | assertEquals(countRowsInTable("FOO"), 0);
219 |
220 | Foo foo = new Foo();
221 | foo.setName("Bob");
222 | fooRepository.save(foo);
223 |
224 | fooRepository.delete(foo.getName());
225 | assertEquals(countRowsInTable("FOO"), 0);
226 |
227 | }
228 |
229 | }
230 | ```
231 |
232 | 在这里我们使用``countRowsInTable("FOO")``来验证数据库结果,这个方法是``AbstractTransactionalTestNGSpringContextTests``对``JdbcTestUtils``的代理。
233 |
234 | 而且要注意的是,每个测试方法在执行完毕后,会自动rollback,所以在``testDelete``的第一行里,我们``assertEquals(countRowsInTable("FOO"), 0)``,这一点和例子1里是不同的。
235 |
236 | 更多关于Spring Testing Framework与Transaction相关的信息,可以见Spring官方文档 [Transaction management][doc-spring-testing-tx]。
237 |
238 | ## 例子3:使用Spring Boot
239 |
240 | [Boot_1_IT.java][src-Boot_1_IT.java]:
241 |
242 | ```java
243 | @SpringBootTest
244 | @SpringBootApplication(scanBasePackageClasses = FooRepository.class)
245 | public class Boot_1_IT extends AbstractTransactionalTestNGSpringContextTests {
246 |
247 | @Autowired
248 | private FooRepository fooRepository;
249 |
250 | @Test
251 | public void testSave() {
252 |
253 | Foo foo = new Foo();
254 | foo.setName("Bob");
255 | fooRepository.save(foo);
256 |
257 | assertEquals(countRowsInTable("FOO"), 1);
258 | countRowsInTableWhere("FOO", "name = 'Bob'");
259 | }
260 |
261 | @Test(dependsOnMethods = "testSave")
262 | public void testDelete() {
263 |
264 | assertEquals(countRowsInTable("FOO"), 0);
265 |
266 | Foo foo = new Foo();
267 | foo.setName("Bob");
268 | fooRepository.save(foo);
269 |
270 | fooRepository.delete(foo.getName());
271 | assertEquals(countRowsInTable("FOO"), 0);
272 |
273 | }
274 |
275 | @AfterTest
276 | public void cleanDb() {
277 | flyway.clean();
278 | }
279 |
280 | }
281 | ```
282 |
283 | 因为使用了Spring Boot来做集成测试,得益于其AutoConfiguration机制,不需要自己构建``DataSource`` 、``JdbcTemplate``和``PlatformTransactionManager``的Bean。
284 |
285 | 并且因为我们已经将``flyway-core``添加到了maven依赖中,Spring Boot会利用flyway来帮助我们初始化数据库,我们需要做的仅仅是将sql文件放到classpath的``db/migration``目录下:
286 |
287 | ``V1.0.0__foo-ddl.sql``:
288 |
289 | ```sql
290 |
291 | CREATE TABLE FOO (
292 | name VARCHAR2(100)
293 | );
294 | ```
295 |
296 | 而且在测试最后,我们利用flyway清空了数据库:
297 |
298 | ```java
299 | @AfterTest
300 | public void cleanDb() {
301 | flyway.clean();
302 | }
303 | ```
304 |
305 | 使用flyway有很多好处:
306 |
307 | 1. 每个sql文件名都规定了版本号
308 | 1. flyway按照版本号顺序执行
309 | 1. 在开发期间,只需要将sql文件放到db/migration目录下就可以了,不需要写类似``EmbeddedDatabaseBuilder.addScript()``这样的代码
310 | 1. 基于以上三点,就能够将数据库初始化SQL语句也纳入到集成测试中来,保证代码配套的SQL语句的正确性
311 | 1. 可以帮助你清空数据库,这在你使用非内存数据库的时候非常有用,因为不管测试前还是测试后,你都需要一个干净的数据库
312 |
313 | ## 参考文档
314 |
315 | 本章节涉及到的Spring Testing Framework JDBC、SQL相关的工具:
316 |
317 | * [Transaction management][doc-spring-testing-tx]
318 | * [Executing SQL scripts][doc-spring-testing-sql]
319 |
320 | 和flyway相关的:
321 |
322 | * [flyway的官方文档][doc-flyway]
323 | * [flway和spring boot的集成][doc-spring-boot-flyway]
324 |
325 | [doc-spring-boot-flyway]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#howto-execute-flyway-database-migrations-on-startup
326 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
327 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
328 | [doc-spring-testing-jdbc]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#integration-testing-support-jdbc
329 | [doc-spring-boot-flyway]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#howto-execute-flyway-database-migrations-on-startup
330 | [site-flyway]: https://flywaydb.org/
331 | [doc-flyway]: https://flywaydb.org/documentation/
332 | [doc-spring-testing-tx]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testcontext-tx
333 | [doc-spring-testing-sql]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testcontext-executing-sql
334 | [src-Foo.java]: rdbs/src/main/java/me/chanjar/domain/Foo.java
335 | [src-FooRepositoryImpl.java]: rdbs/src/main/java/me/chanjar/domain/FooRepositoryImpl.java
336 | [src-foo-ddl.sql]: rdbs/src/main/resources/me/chanjar/domain/foo-ddl.sql
337 | [src-Spring_1_IT.java]: rdbs/src/test/java/me/chanjar/spring1/Spring_1_IT.java
338 | [src-Spring_1_IT_Configuration.java]: rdbs/src/test/java/me/chanjar/spring1/Spring_1_IT_Configuration.java
339 | [src-Spring_2_IT.java]: rdbs/src/test/java/me/chanjar/spring2/Spring_2_IT.java
340 | [src-Spring_2_IT_Configuration.java]: rdbs/src/test/java/me/chanjar/spring2/Spring_2_IT_Configuration.java
341 | [src-Boot_1_IT.java]: rdbs/src/test/java/me/chanjar/springboot1/Boot_1_IT.java
342 |
--------------------------------------------------------------------------------
/chapter_4_s2_using_docker.md:
--------------------------------------------------------------------------------
1 | # Chapter 4: 测试关系型数据库 - 使用Docker创建临时数据库
2 |
3 | 在[Chapter 4: 测试关系型数据库 - 基本做法][chapter_4_s1_basic]里我们使用的是H2数据库,这是为了让你免去你去安装/配置一个数据库的工作,能够尽快的了解到集成测试的过程。
4 |
5 | 在文章里也说了:
6 |
7 | > 在真实的开发环境中,集成测试用数据库应该和最终的生产数据库保持一致
8 |
9 | 那么很容易就能想到两种解决方案:
10 |
11 | 1. 开发团队使用共用同一个数据库。这样做的问题在于:当有多个集成测试同时在跑时,会产生错误的测试结果。
12 | 2. 每个人使用自己的数据库。这样做的问题在于让开发人员维护MySQL数据库挺麻烦的。
13 |
14 | 那么做到能否这样呢?
15 |
16 | 1. 测试启动前,创建一个MySQL数据库
17 | 2. 测试过程中连接到这个数据库
18 | 3. 测试结束后,删除这个MySQL数据库
19 |
20 | So, Docker comes to the rescue。
21 |
22 | 我们还是会以[Chapter 4: 测试关系型数据库 - 基本做法][chapter_4_s1_basic]里的`FooRepositoryImpl`来做集成测试([代码在这里][code-rdbs-docker])。下面来讲解具体步骤:
23 |
24 | ## 安装Docker
25 |
26 | 请查阅官方文档。并且掌握Docker的基本概念。
27 |
28 | ## 配置properties
29 |
30 | 先定义几个properties:
31 |
32 | ```xml
33 |
34 | 0.28.0
35 | 2.22.0
36 | 2.19
37 |
38 | false
39 |
40 | ${skipTests}
41 |
42 | ${skipTests}
43 |
44 | ```
45 |
46 | ## 配置fabric8 docker-maven-plugin
47 |
48 | [farbic8 docker-maven-plugin][fabric8-dmp]顾名思义就是一个能够使用docker的maven plugin。它主要功能有二:
49 |
50 | 1. [创建Docker image][fabric8-dmp-build]
51 | 2. [启动Docker container][fabric8-dmp-start]
52 |
53 | 我们这里使用**启动Docker container**的功能。
54 |
55 | 大致配置如下
56 |
57 | ```xml
58 |
59 | io.fabric8
60 | docker-maven-plugin
61 | ${fabric8.dmp.version}
62 |
63 |
64 |
65 | ${skipITs}
66 |
67 |
68 |
69 | mysql:8
70 |
71 |
72 |
73 |
75 | docker-mysql.port:3306
76 |
77 |
78 |
79 | 123456
80 | test
81 | foo
82 | bar
83 |
84 |
85 |
86 |
87 | MySQL init process done. Ready for start up.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | start
99 | pre-integration-test
100 |
101 | start
102 |
103 |
104 |
105 |
106 | stop
107 | post-integration-test
108 |
109 | stop
110 |
111 |
112 |
113 |
114 | ```
115 |
116 | ## 配置maven-failsafe-plugin
117 |
118 | maven-failsafe-plugin用来执行集成测试`*IT.java`。
119 |
120 | ```xml
121 |
122 | org.apache.maven.plugins
123 | maven-failsafe-plugin
124 | ${maven-failsafe-plugin.version}
125 |
126 |
127 | integration-test
128 |
129 | integration-test
130 |
131 |
132 |
133 | verify
134 |
135 | verify
136 |
137 |
138 |
139 |
140 |
141 | ${skipTests}
142 |
143 | ${skipITs}
144 |
147 |
148 | jdbc:mysql://localhost:${docker-mysql.port}/test
149 | foo
150 | bar
151 |
152 |
153 |
154 | ```
155 |
156 | ## 配置maven-surefire-plugin
157 |
158 | maven-surefire-plugin用来执行单元测试`*Test.java`。
159 |
160 | ```xml
161 |
162 | org.apache.maven.plugins
163 | maven-surefire-plugin
164 | ${maven-surefire-plugin.version}
165 |
166 | ${skipUTs}
167 |
168 |
169 | ```
170 |
171 | ## 执行
172 |
173 | 三种常见用法:
174 |
175 | * `mvn clean integration-test`,会启动docker container、运行集成测试。这个很有用,如果集成测试失败,那么你还可以连接到MySQL数据库查看情况。
176 | * `mvn clean verify`,会执行`mvn integration-test`、删除docker container。
177 | * `mvn clean install`,会执`mvn verify`,并将包安装到本地maven 仓库。
178 |
179 | 配合`-DskipTests`、`-DskipITs`、`-DskipUTs`可以控制是否跳过所有测试、紧跳过集成测试、仅跳过单元测试。
180 |
181 | 下面是`mvn clean verify`的日志:
182 |
183 | ```txt
184 | ...
185 | [INFO] --- docker-maven-plugin:0.28.0:start (start) @ spring-test-examples-rdbs-docker ---
186 | [INFO] DOCKER> [mysql:8]: Start container f683aadfe8ba
187 | [INFO] DOCKER> Pattern 'MySQL init process done. Ready for start up.' matched for container f683aadfe8ba
188 | [INFO] DOCKER> [mysql:8]: Waited on log out 'MySQL init process done. Ready for start up.' 13717 ms
189 | [INFO]
190 | [INFO] --- maven-failsafe-plugin:2.22.1:integration-test (integration-test) @ spring-test-examples-rdbs-docker ---
191 | [INFO]
192 | [INFO] -------------------------------------------------------
193 | [INFO] T E S T S
194 | [INFO] -------------------------------------------------------
195 | ...
196 | [INFO]
197 | [INFO] Results:
198 | [INFO]
199 | [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
200 | [INFO]
201 | [INFO]
202 | [INFO] --- docker-maven-plugin:0.28.0:stop (stop) @ spring-test-examples-rdbs-docker ---
203 | [INFO] DOCKER> [mysql:8]: Stop and removed container f683aadfe8ba after 0 ms
204 | [INFO]
205 | [INFO] --- maven-failsafe-plugin:2.22.1:verify (verify) @ spring-test-examples-rdbs-docker ---
206 | [INFO] ------------------------------------------------------------------------
207 | [INFO] BUILD SUCCESS
208 | [INFO] ------------------------------------------------------------------------
209 | ...
210 | ```
211 |
212 | 可以看到fabric8 dmp在集成测试前后start和stop容器的相关日志,且测试成功。
213 |
214 | 如何找到MySQL的端口开在哪一个呢?运行`docker ps`查看端口(注意下面的`0.0.0.0:32798->3306/tcp`):
215 |
216 | ```txt
217 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
218 | a1f4b51d7c75 mysql:8 ... ... Up 19... 33060/tcp, 0.0.0.0:32798->3306/tcp mysql-1
219 | ```
220 |
221 | ## 在Intellij IDEA中运行JUnit的问题
222 |
223 | 本文中用到的pom.xml同样可适用于JUnit编写的单元、集成测试。
224 |
225 | 在Intellij IDEA中直接执行JUnit测试的时候会读取maven-failsafe-plugin的`systemPropertyVariables`,这样会产生问题:
226 | 你想用一个临时的application.properties来执行JUnit测试,但是IDEA的JUnit插件读取了maven-failsafe-plugin的`systemPropertyVariables`,
227 | 而这些东西覆盖了application.properties里的内容,并且它们的值还可能是错的。
228 |
229 | 解决办法是将maven-failsafe-plugin和docker-maven-plugin放到profile中:
230 |
231 | ```xml
232 |
233 |
234 | integration-test
235 |
236 |
237 |
238 | org.apache.maven.plugins
239 | maven-failsafe-plugin
240 | ${maven-failsafe-plugin.version}
241 | ...
242 |
243 |
244 |
245 | io.fabric8
246 | docker-maven-plugin
247 | ${fabric8.dmp.version}
248 | ...
249 |
250 |
251 |
252 |
253 |
254 |
255 | ```
256 |
257 | 然后使用`mvn clean install -Pintegration-test`来启用它。
258 |
259 | ## 参考文档
260 |
261 | * [Fabric8 dmp][fabric8-dmp]
262 | * [Spring boot - Externalized Configuration][doc-spring-boot-ext-config]
263 |
264 |
265 | [chapter_4_s1_basic]: chapter_4_s1_basic.md
266 | [code-rdbs-docker]:rdbs-docker
267 | [fabric8-dmp]: https://dmp.fabric8.io/
268 |
269 | [fabric8-dmp-build]: https://dmp.fabric8.io/#docker:build
270 | [fabric8-dmp-start]: https://dmp.fabric8.io/#docker:start
271 |
272 | [doc-spring-boot-ext-config]: https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/html/boot-features-external-config.html
273 |
--------------------------------------------------------------------------------
/chapter_5_mvc.md:
--------------------------------------------------------------------------------
1 | # Chapter 5: 测试Spring MVC
2 |
3 | [Spring Testing Framework][doc-spring-framework-testing]提供了[Spring MVC Test Framework][doc-spring-mvc-test-framework],能够很方便的来测试Controller。同时Spring Boot也提供了[Auto-configured Spring MVC tests][doc-auto-configured-spring-mvc-tests]更进一步简化了测试需要的配置工作。
4 |
5 | 本章节将分别举例说明在不使用Spring Boot和使用Spring Boot下如何对Spring MVC进行测试。
6 |
7 | ## 例子1:Spring
8 |
9 | 测试Spring MVC的关键是使用`MockMvc`对象,利用它我们能够在不需启动Servlet容器的情况下测试Controller的行为。
10 |
11 | 源代码[SpringMvc_1_Test.java][src-SpringMvc_1_Test.java]:
12 |
13 | ```java
14 | @EnableWebMvc
15 | @WebAppConfiguration
16 | @ContextConfiguration(classes = { FooController.class, FooImpl.class })
17 | public class SpringMvc_1_Test extends AbstractTestNGSpringContextTests {
18 |
19 | @Autowired
20 | private WebApplicationContext wac;
21 |
22 | private MockMvc mvc;
23 |
24 | @BeforeMethod
25 | public void prepareMockMvc() {
26 | this.mvc = webAppContextSetup(wac).build();
27 | }
28 |
29 | @Test
30 | public void testController() throws Exception {
31 |
32 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
33 | .andDo(print())
34 | .andExpect(status().isOk())
35 | .andExpect(content().string("true"));
36 |
37 | }
38 |
39 | }
40 | ```
41 |
42 | 在这段代码里,主要有三个步骤:
43 |
44 | 1. 将测试类标记为`@WebAppConfiguration`
45 | 1. 通过`webAppContextSetup(wac).build()`构建`MockMvc`
46 | 1. 利用`MockMvc`对结果进行判断
47 |
48 | ## 例子2:Spring + Mock
49 |
50 | 在例子1里,`FooController`使用了一个实体`FooImpl`的Bean,实际上我们也可以提供一个`Foo`的mock bean来做测试,这样就能够更多的控制测试过程。如果你还不知道Mock那么请看[Chapter 3: 使用Mockito][chapter_3_mockito]。
51 |
52 | 源代码[SpringMvc_2_Test.java][src-SpringMvc_2_Test.java]:
53 |
54 | ```java
55 | @EnableWebMvc
56 | @WebAppConfiguration
57 | @ContextConfiguration(classes = { FooController.class })
58 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
59 | public class SpringMvc_2_Test extends AbstractTestNGSpringContextTests {
60 |
61 | @Autowired
62 | private WebApplicationContext wac;
63 |
64 | @MockBean
65 | private Foo foo;
66 |
67 | private MockMvc mvc;
68 |
69 | @BeforeMethod
70 | public void prepareMockMvc() {
71 | this.mvc = webAppContextSetup(wac).build();
72 | }
73 |
74 | @Test
75 | public void testController() throws Exception {
76 |
77 | when(foo.checkCodeDuplicate(anyString())).thenReturn(true);
78 |
79 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
80 | .andDo(print())
81 | .andExpect(status().isOk())
82 | .andExpect(content().string("true"));
83 |
84 | }
85 |
86 | }
87 | ```
88 |
89 |
90 | ## 例子3:Spring Boot
91 |
92 | Spring Boot提供了`@WebMvcTest`更进一步简化了对于Spring MVC的测试,我们提供了对应例子1的Spring Boot版本。
93 |
94 | 源代码[BootMvc_1_Test.java][src-BootMvc_1_Test.java]:
95 |
96 | ```java
97 | @WebMvcTest
98 | @ContextConfiguration(classes = { FooController.class, FooImpl.class })
99 | public class BootMvc_1_Test extends AbstractTestNGSpringContextTests {
100 |
101 | @Autowired
102 | private MockMvc mvc;
103 |
104 | @Test
105 | public void testController() throws Exception {
106 |
107 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
108 | .andDo(print())
109 | .andExpect(status().isOk())
110 | .andExpect(content().string("true"));
111 |
112 | }
113 |
114 | }
115 | ```
116 |
117 | 在这里,我们不需要自己构建`MockMvc`,直接使用`@Autowired`注入就行了,是不是很方便?
118 |
119 | ## 例子4:Spring Boot + Mock
120 |
121 | 这个是对应例子2的Spring Boot版本,源代码[BootMvc_2_Test.java][src-BootMvc_2_Test.java]:
122 |
123 | ```java
124 | @WebMvcTest
125 | @ContextConfiguration(classes = { FooController.class })
126 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
127 | public class BootMvc_2_Test extends AbstractTestNGSpringContextTests {
128 |
129 | @Autowired
130 | private MockMvc mvc;
131 |
132 | @MockBean
133 | private Foo foo;
134 |
135 | @Test
136 | public void testController() throws Exception {
137 |
138 | when(foo.checkCodeDuplicate(anyString())).thenReturn(true);
139 |
140 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
141 | .andDo(print())
142 | .andExpect(status().isOk())
143 | .andExpect(content().string("true"));
144 |
145 | }
146 |
147 | }
148 | ```
149 |
150 |
151 | ## 参考文档
152 |
153 | * [Loading a WebApplicationContext][doc-spring-WebApplicationContext]
154 | * [Spring MVC Test Framework][doc-spring-mvc-test-framework]
155 | * [Spring MVC Official Sample Tests][gh-spring-mvc-official-sample-tests]
156 | * [Spring MVC showcase - with full mvc test][gh-spring-mvc-showcase]
157 | * [Auto-configured Spring MVC tests][doc-auto-configured-spring-mvc-tests]
158 | * [Spring Framework Testing][doc-spring-framework-testing]
159 | * [Spring Boot Testing][doc-spring-boot-testing]
160 | * [Spring Guides - Testing the Web Layer][guide-testing-the-web-layer]
161 |
162 | [chapter_3_mockito]: chapter_3_mockito.md
163 | [guide-testing-the-web-layer]: https://spring.io/guides/gs/testing-web/
164 | [doc-spring-framework-testing]: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing
165 | [doc-spring-WebApplicationContext]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-web
166 | [doc-spring-boot-testing]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing
167 | [javadoc-AutoConfigureMockMvc]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.html
168 | [doc-auto-configured-spring-mvc-tests]: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests
169 | [doc-spring-mvc-test-framework]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#spring-mvc-test-framework
170 | [gh-spring-mvc-official-sample-tests]: https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples
171 | [gh-spring-mvc-showcase]: https://github.com/spring-projects/spring-mvc-showcase
172 | [src-SpringMvc_1_Test.java]: mvc/src/test/java/me/chanjar/spring1/SpringMvc_1_Test.java
173 | [src-SpringMvc_2_Test.java]: mvc/src/test/java/me/chanjar/spring2/SpringMvc_2_Test.java
174 | [src-BootMvc_1_Test.java]: mvc/src/test/java/me/chanjar/springboot1/BootMvc_1_Test.java
175 | [src-BootMvc_2_Test.java]: mvc/src/test/java/me/chanjar/springboot2/BootMvc_2_Test.java
176 |
--------------------------------------------------------------------------------
/chapter_6_aop.md:
--------------------------------------------------------------------------------
1 | # Chapter 6: 测试AOP
2 |
3 | Spring提供了一套[AOP工具][doc-spring-aop],但是当你把各种Aspect写完之后,如何确定这些Aspect都正确的应用到目标Bean上了呢?本章将举例说明如何对Spring AOP做测试。
4 |
5 | 首先先来看我们事先定义的Bean以及Aspect。
6 |
7 | [FooServiceImpl][src-FooServiceImpl]:
8 |
9 | ```java
10 | @Component
11 | public class FooServiceImpl implements FooService {
12 |
13 | private int count;
14 |
15 | @Override
16 | public int incrementAndGet() {
17 | count++;
18 | return count;
19 | }
20 |
21 | }
22 | ```
23 |
24 | [FooAspect][src-FooAspect]:
25 |
26 | ```java
27 | @Component
28 | @Aspect
29 | public class FooAspect {
30 |
31 | @Pointcut("execution(* me.chanjar.aop.service.FooServiceImpl.incrementAndGet())")
32 | public void pointcut() {
33 | }
34 |
35 | @Around("pointcut()")
36 | public int changeIncrementAndGet(ProceedingJoinPoint pjp) {
37 | return 0;
38 | }
39 |
40 | }
41 | ```
42 |
43 | 可以看到`FooAspect`会修改`FooServiceImpl.incrementAndGet`方法的返回值,使其返回0。
44 |
45 | ## 例子1:测试FooService的行为
46 |
47 | 最简单的测试方法就是直接调用`FooServiceImpl.incrementAndGet`,看看它是否使用返回0。
48 |
49 | [SpringAop_1_Test][src-ex1-SpringAop_1_Test]:
50 |
51 | ```java
52 | @ContextConfiguration(classes = { SpringAopTest.class, AopConfig.class })
53 | public class SpringAop_1_Test extends AbstractTestNGSpringContextTests {
54 |
55 | @Autowired
56 | private FooService fooService;
57 |
58 | @Test
59 | public void testFooService() {
60 |
61 | assertNotEquals(fooService.getClass(), FooServiceImpl.class);
62 |
63 | assertTrue(AopUtils.isAopProxy(fooService));
64 | assertTrue(AopUtils.isCglibProxy(fooService));
65 |
66 | assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class);
67 |
68 | assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class);
69 | assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
70 |
71 | assertEquals(fooService.incrementAndGet(), 0);
72 | assertEquals(fooService.incrementAndGet(), 0);
73 |
74 | }
75 |
76 | }
77 | ```
78 |
79 | 先看这段代码:
80 |
81 | ```java
82 | assertNotEquals(fooService.getClass(), FooServiceImpl.class);
83 |
84 | assertTrue(AopUtils.isAopProxy(fooService));
85 | assertTrue(AopUtils.isCglibProxy(fooService));
86 |
87 | assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class);
88 |
89 | assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class);
90 | assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
91 | ```
92 |
93 | 这些是利用Spring提供的[AopUtils][javadoc-spring-AopUtils]、[AopTestUtils][javadoc-spring-AopTestUtils]和[AopProxyUtils][javadoc-spring-AopProxyUtils]来判断`FooServiceImpl` Bean是否被代理了(Spring AOP的实现是通过[动态代理][javadoc-spring-aop-proxying]来做的)。
94 |
95 | 但是证明`FooServiceImpl` Bean被代理并不意味着`FooAspect`生效了(假设此时有多个`@Aspect`),那么我们还需要验证`FooServiceImpl.incrementAndGet`的行为:
96 |
97 | ```java
98 | assertEquals(fooService.incrementAndGet(), 0);
99 | assertEquals(fooService.incrementAndGet(), 0);
100 | ```
101 |
102 | ## 例子2:测试FooAspect的行为
103 |
104 | 但是总有一些时候我们是无法通过例子1的方法来测试Bean是否被正确的advised的:
105 |
106 | 1. advised方法没有返回值
107 | 1. Aspect不会修改advised方法的返回值(比如:做日志)
108 |
109 | 那么这个时候怎么测试呢?此时我们就需要用到Mockito的Spy方法结合Spring Testing工具来测试。
110 |
111 | [SpringAop_2_Test][src-ex2-SpringAop_2_Test]:
112 |
113 | ```java
114 | @ContextConfiguration(classes = { SpringAop_2_Test.class, AopConfig.class })
115 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
116 | public class SpringAop_2_Test extends AbstractTestNGSpringContextTests {
117 |
118 | @SpyBean
119 | private FooAspect fooAspect;
120 |
121 | @Autowired
122 | private FooService fooService;
123 |
124 | @Test
125 | public void testFooService() {
126 |
127 | // ...
128 | verify(fooAspect, times(2)).changeIncrementAndGet(any());
129 |
130 | }
131 |
132 | }
133 | ```
134 |
135 | 这段代码和例子1有三点区别:
136 |
137 | 1. 启用了``MockitoTestExecutionListener``,这样能够开启Mockito的支持(回顾一下[Chapter 3: 使用Mockito][chapter_3_mockito.md])
138 | 1. ``@SpyBean private FooAspect fooAspect``,这样能够声明一个被Mockito.spy过的Bean
139 | 1. ``verify(fooAspect, times(2)).changeIncrementAndGet(any())``,使用Mockito测试``FooAspect.changeIncrementAndGet``是否被调用了两次
140 |
141 | 上面的测试代码测试的是``FooAspect``的行为,而不是``FooServiceImpl``的行为,这种测试方法更为通用。
142 |
143 | ## 例子3:Spring Boot的例子
144 |
145 | 上面两个例子使用的是Spring Testing工具,下面举例Spring Boot Testing工具如何测AOP(其实大同小异):
146 |
147 | [SpringBootAopTest][src-ex3-SpringBootAopTest]:
148 |
149 | ```java
150 | @SpringBootTest(classes = { SpringBootAopTest.class, AopConfig.class })
151 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
152 | public class SpringBootAopTest extends AbstractTestNGSpringContextTests {
153 |
154 | @SpyBean
155 | private FooAspect fooAspect;
156 |
157 | @Autowired
158 | private FooService fooService;
159 |
160 | @Test
161 | public void testFooService() {
162 |
163 | // ...
164 | verify(fooAspect, times(2)).changeIncrementAndGet(any());
165 |
166 | }
167 |
168 | }
169 | ```
170 |
171 | ## 参考文档
172 |
173 | * [Aspect Oriented Programming with Spring][doc-spring-aop]
174 | * [AopUtils][javadoc-spring-AopUtils]
175 | * [AopTestUtils][javadoc-spring-AopTestUtils]
176 | * [AopProxyUtils][javadoc-spring-AopProxyUtils]
177 | * [spring源码EnableAspectJAutoProxyTests][src-gh-EnableAspectJAutoProxyTests]
178 | * [spring源码AbstractAspectJAdvisorFactoryTests][src-gh-AbstractAspectJAdvisorFactoryTests]
179 |
180 | [chapter_3_mockito.md]: chapter_3_mockito.md
181 | [doc-spring-aop]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/aop.html
182 | [javadoc-spring-AopUtils]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/aop/support/AopUtils.html
183 | [javadoc-spring-AopTestUtils]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/test/util/AopTestUtils.html
184 | [javadoc-spring-AopProxyUtils]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/aop/framework/AopProxyUtils.html
185 | [javadoc-spring-aop-proxying]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/aop.html#aop-proxying
186 |
187 | [src-FooServiceImpl]: aop/src/main/java/me/chanjar/aop/service/FooServiceImpl.java
188 | [src-FooAspect]: aop/src/main/java/me/chanjar/aop/aspect/FooAspect.java
189 | [src-ex1-SpringAop_1_Test]: aop/src/test/java/me/chanjar/aop/ex1/SpringAop_1_Test.java
190 | [src-ex2-SpringAop_2_Test]: aop/src/test/java/me/chanjar/aop/ex2/SpringAop_2_Test.java
191 | [src-ex3-SpringBootAopTest]: aop/src/test/java/me/chanjar/aop/ex3/SpringBootAopTest.java
192 | [src-gh-EnableAspectJAutoProxyTests]: https://github.com/spring-projects/spring-framework/blob/v4.3.9.RELEASE/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java
193 | [src-gh-AbstractAspectJAdvisorFactoryTests]: https://github.com/spring-projects/spring-framework/blob/v4.3.9.RELEASE/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java
194 |
--------------------------------------------------------------------------------
/chapter_8_share_test_config.md:
--------------------------------------------------------------------------------
1 | # Chapter 8: 共享测试配置
2 |
3 | 在[使用Spring Boot Testing工具][chapter_1_s3_spring_boot_testing]中提到:
4 |
5 | > 在测试代码之间尽量做到配置共用。
6 | > ...
7 | > 能够有效利用Spring TestContext Framework的[缓存机制][doc-context-caching],ApplicationContext只会创建一次,后面的测试会直接用已创建的那个,加快测试代码运行速度。
8 |
9 | 本章将列举几种共享测试配置的方法
10 |
11 | ## @Configuration
12 |
13 | 我们可以将测试配置放在一个@Configuration里,然后在测试@SpringBootTest或ContextConfiguration中引用它。
14 |
15 |
16 | [PlainConfiguration][src-ex1-PlainConfiguration.java]:
17 |
18 | ```java
19 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
20 | public class PlainConfiguration {
21 | }
22 | ```
23 |
24 | [FooRepositoryIT][src-ex1-FooRepositoryIT.java]:
25 |
26 | ```java
27 | @SpringBootTest(classes = PlainConfiguration.class)
28 | public class FooRepositoryIT extends ...
29 | ```
30 |
31 | ## @Configuration on interface
32 |
33 | 也可以把@Configuration放到一个interface上。
34 |
35 | [PlainConfiguration][src-ex2-InterfaceConfiguration.java]:
36 |
37 | ```java
38 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
39 | public interface InterfaceConfiguration {
40 | }
41 | ```
42 |
43 | [FooRepositoryIT][src-ex2-FooRepositoryIT.java]:
44 |
45 | ```java
46 | @SpringBootTest(classes = InterfaceConfiguration.class)
47 | public class FooRepositoryIT extends ...
48 | ```
49 | ## Annotation
50 |
51 | 也可以利用Spring的[Meta-annotations][doc-spring-meta-annotations]及[自定义机制][doc-spring-annotation-programming-model],提供自己的Annotation用在测试配置上。
52 |
53 | [PlainConfiguration][src-ex3-AnnotationConfiguration.java]:
54 |
55 | ```java
56 | @Target(ElementType.TYPE)
57 | @Retention(RetentionPolicy.RUNTIME)
58 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
59 | public @interface AnnotationConfiguration {
60 | }
61 | ```
62 |
63 | [FooRepositoryIT][src-ex3-FooRepositoryIT.java]:
64 |
65 | ```java
66 | @SpringBootTest(classes = FooRepositoryIT.class)
67 | @AnnotationConfiguration
68 | public class FooRepositoryIT extends ...
69 | ```
70 | ## 参考文档
71 |
72 | * [Meta-annotations][doc-spring-meta-annotations]
73 | * [Meta-Annotation Support for Testing][doc-spring-meta-annotations-for-testing]
74 | * [Spring Annotation Programming Model][doc-spring-annotation-programming-model]
75 |
76 | [chapter_1_s3_spring_boot_testing]: chapter_1_s3_spring_boot_testing.md
77 | [doc-context-caching]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-caching
78 | [doc-spring-meta-annotations-for-testing]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#integration-testing-annotations-meta
79 | [doc-spring-meta-annotations]: https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-meta-annotations
80 | [doc-spring-annotation-programming-model]: https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model
81 | [src-ex1-PlainConfiguration.java]: share-config/src/test/java/me/chanjar/shareconfig/testconfig/PlainConfiguration.java
82 | [src-ex1-FooRepositoryIT.java]: share-config/src/test/java/me/chanjar/shareconfig/configuration/FooRepositoryIT.java
83 | [src-ex2-InterfaceConfiguration.java]: share-config/src/test/java/me/chanjar/shareconfig/testconfig/InterfaceConfiguration.java
84 | [src-ex2-FooRepositoryIT.java]: share-config/src/test/java/me/chanjar/shareconfig/inter/FooRepositoryIT.java
85 | [src-ex3-AnnotationConfiguration.java]: share-config/src/test/java/me/chanjar/shareconfig/annotation/FooRepositoryIT.java
86 | [src-ex3-FooRepositoryIT.java]: share-config/src/test/java/me/chanjar/shareconfig/testconfig/AnnotationConfiguration.java
87 |
--------------------------------------------------------------------------------
/configuration/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-configuration
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.slf4j
25 | slf4j-api
26 |
27 |
28 |
29 | ch.qos.logback
30 | logback-classic
31 |
32 |
33 |
34 |
35 | org.testng
36 | testng
37 | test
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.apache.maven.plugins
52 | maven-jar-plugin
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/configuration/src/main/java/me/chanjar/configuration/service/Bar.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.service;
2 |
3 | public class Bar {
4 |
5 | private final String name;
6 |
7 | public Bar(String name) {
8 | this.name = name;
9 | }
10 |
11 | public String getName() {
12 | return name;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/configuration/src/main/java/me/chanjar/configuration/service/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.service;
2 |
3 | public class Foo {
4 | }
5 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex1/FooConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex1;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | @Configuration
8 | public class FooConfiguration {
9 |
10 | @Bean
11 | public Foo foo() {
12 | return new Foo();
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex1/FooConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex1;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5 | import org.testng.annotations.AfterMethod;
6 | import org.testng.annotations.BeforeMethod;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertNotNull;
10 |
11 | public class FooConfigurationTest {
12 |
13 | private AnnotationConfigApplicationContext context;
14 |
15 | @BeforeMethod
16 | public void init() {
17 | context = new AnnotationConfigApplicationContext();
18 | }
19 |
20 | @AfterMethod(alwaysRun = true)
21 | public void reset() {
22 | context.close();
23 | }
24 |
25 | @Test
26 | public void testFooCreation() {
27 | context.register(FooConfiguration.class);
28 | context.refresh();
29 | assertNotNull(context.getBean(Foo.class));
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex2/FooConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex2;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.context.annotation.*;
5 | import org.springframework.core.type.AnnotatedTypeMetadata;
6 |
7 | @Configuration
8 | public class FooConfiguration {
9 |
10 | @Bean
11 | @Conditional(FooCondition.class)
12 | public Foo foo() {
13 | return new Foo();
14 | }
15 |
16 | public static class FooCondition implements Condition {
17 |
18 | @Override
19 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
20 | if (context.getEnvironment() != null) {
21 | Boolean property = context.getEnvironment().getProperty("foo.create", Boolean.class);
22 | return Boolean.TRUE.equals(property);
23 | }
24 | return false;
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex2/FooConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex2;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.beans.factory.NoSuchBeanDefinitionException;
5 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
6 | import org.springframework.core.env.MapPropertySource;
7 | import org.testng.annotations.AfterMethod;
8 | import org.testng.annotations.BeforeMethod;
9 | import org.testng.annotations.Test;
10 |
11 | import java.util.Collections;
12 |
13 | import static org.testng.Assert.assertNotNull;
14 |
15 | public class FooConfigurationTest {
16 |
17 | private AnnotationConfigApplicationContext context;
18 |
19 | @BeforeMethod
20 | public void init() {
21 | context = new AnnotationConfigApplicationContext();
22 | }
23 |
24 | @AfterMethod(alwaysRun = true)
25 | public void reset() {
26 | context.close();
27 | }
28 |
29 | @Test(expectedExceptions = NoSuchBeanDefinitionException.class)
30 | public void testFooCreatePropertyNull() {
31 | context.register(FooConfiguration.class);
32 | context.refresh();
33 | context.getBean(Foo.class);
34 | }
35 |
36 | @Test
37 | public void testFooCreatePropertyTrue() {
38 | context.getEnvironment().getPropertySources().addLast(
39 | new MapPropertySource("test", Collections.singletonMap("foo.create", "true"))
40 | );
41 | context.register(FooConfiguration.class);
42 | context.refresh();
43 | assertNotNull(context.getBean(Foo.class));
44 | }
45 |
46 | @Test(expectedExceptions = NoSuchBeanDefinitionException.class)
47 | public void testFooCreatePropertyFalse() {
48 | context.getEnvironment().getPropertySources().addLast(
49 | new MapPropertySource("test", Collections.singletonMap("foo.create", "false"))
50 | );
51 | context.register(FooConfiguration.class);
52 | context.refresh();
53 | assertNotNull(context.getBean(Foo.class));
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex3/FooConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex3;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | @Configuration
9 | public class FooConfiguration {
10 |
11 | @Bean
12 | @ConditionalOnProperty(prefix = "foo", name = "create", havingValue = "true")
13 | public Foo foo() {
14 | return new Foo();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex3/FooConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex3;
2 |
3 | import me.chanjar.configuration.service.Foo;
4 | import org.springframework.beans.factory.NoSuchBeanDefinitionException;
5 | import org.springframework.boot.test.util.EnvironmentTestUtils;
6 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
7 | import org.testng.annotations.AfterMethod;
8 | import org.testng.annotations.BeforeMethod;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.testng.Assert.assertNotNull;
12 |
13 | public class FooConfigurationTest {
14 |
15 | private AnnotationConfigApplicationContext context;
16 |
17 | @BeforeMethod
18 | public void init() {
19 | context = new AnnotationConfigApplicationContext();
20 | }
21 |
22 | @AfterMethod(alwaysRun = true)
23 | public void reset() {
24 | context.close();
25 | }
26 |
27 | @Test(expectedExceptions = NoSuchBeanDefinitionException.class)
28 | public void testFooCreatePropertyNull() {
29 | context.register(FooConfiguration.class);
30 | context.refresh();
31 | context.getBean(Foo.class);
32 | }
33 |
34 | @Test
35 | public void testFooCreatePropertyTrue() {
36 | EnvironmentTestUtils.addEnvironment(context, "foo.create=true");
37 | context.register(FooConfiguration.class);
38 | context.refresh();
39 | assertNotNull(context.getBean(Foo.class));
40 | }
41 |
42 | @Test(expectedExceptions = NoSuchBeanDefinitionException.class)
43 | public void testFooCreatePropertyFalse() {
44 | EnvironmentTestUtils.addEnvironment(context, "foo.create=false");
45 | context.register(FooConfiguration.class);
46 | context.refresh();
47 | assertNotNull(context.getBean(Foo.class));
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex4/BarConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex4;
2 |
3 | import me.chanjar.configuration.service.Bar;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | @Configuration
11 | @EnableConfigurationProperties(BarConfiguration.BarProperties.class)
12 | public class BarConfiguration {
13 |
14 | @Autowired
15 | private BarProperties barProperties;
16 |
17 | @Bean
18 | public Bar bar() {
19 | return new Bar(barProperties.getName());
20 | }
21 |
22 | @ConfigurationProperties("bar")
23 | public static class BarProperties {
24 |
25 | private String name;
26 |
27 | public String getName() {
28 | return name;
29 | }
30 |
31 | public void setName(String name) {
32 | this.name = name;
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/configuration/src/test/java/me/chanjar/configuration/ex4/BarConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.configuration.ex4;
2 |
3 | import me.chanjar.configuration.service.Bar;
4 | import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
5 | import org.springframework.boot.test.util.EnvironmentTestUtils;
6 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
7 | import org.testng.annotations.AfterMethod;
8 | import org.testng.annotations.BeforeMethod;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.testng.Assert.assertEquals;
12 |
13 | public class BarConfigurationTest {
14 |
15 | private AnnotationConfigApplicationContext context;
16 |
17 | @BeforeMethod
18 | public void init() {
19 | context = new AnnotationConfigApplicationContext();
20 | }
21 |
22 | @AfterMethod(alwaysRun = true)
23 | public void reset() {
24 | context.close();
25 | }
26 |
27 | @Test
28 | public void testBarCreation() {
29 | EnvironmentTestUtils.addEnvironment(context, "bar.name=test");
30 | context.register(BarConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
31 | context.refresh();
32 | assertEquals(context.getBean(Bar.class).getName(), "test");
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/mock/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-mock
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.slf4j
25 | slf4j-api
26 |
27 |
28 |
29 | ch.qos.logback
30 | logback-classic
31 |
32 |
33 |
34 |
35 | org.testng
36 | testng
37 | test
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.apache.maven.plugins
52 | maven-jar-plugin
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/mock/src/main/java/me/chanjar/common/Bar.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.common;
2 |
3 | import java.util.Set;
4 |
5 | public interface Bar {
6 |
7 | Set getAllCodes();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/mock/src/main/java/me/chanjar/common/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.common;
2 |
3 | public interface Foo {
4 |
5 | boolean checkCodeDuplicate(String code);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/mock/src/main/java/me/chanjar/common/FooImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.common;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component
7 | public class FooImpl implements Foo {
8 |
9 | private Bar bar;
10 |
11 | @Override
12 | public boolean checkCodeDuplicate(String code) {
13 | return bar.getAllCodes().contains(code);
14 | }
15 |
16 | @Autowired
17 | public void setBar(Bar bar) {
18 | this.bar = bar;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/mockito/MockitoTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.mockito;
2 |
3 | import me.chanjar.common.Bar;
4 | import me.chanjar.common.FooImpl;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.Mock;
7 | import org.mockito.MockitoAnnotations;
8 | import org.testng.annotations.BeforeMethod;
9 | import org.testng.annotations.Test;
10 |
11 | import java.util.Collections;
12 |
13 | import static org.mockito.Mockito.when;
14 | import static org.testng.Assert.assertEquals;
15 |
16 | public class MockitoTest {
17 |
18 | @Mock
19 | private Bar bar;
20 |
21 | @InjectMocks
22 | private FooImpl foo;
23 |
24 | @BeforeMethod(alwaysRun = true)
25 | public void initMock() {
26 | MockitoAnnotations.initMocks(this);
27 | }
28 |
29 | @Test
30 | public void testCheckCodeDuplicate() throws Exception {
31 |
32 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
33 | assertEquals(foo.checkCodeDuplicate("123"), true);
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/no_mock/NoMockTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.no_mock;
2 |
3 | import me.chanjar.common.Bar;
4 | import me.chanjar.common.FooImpl;
5 | import org.testng.annotations.Test;
6 |
7 | import java.util.Collections;
8 | import java.util.Set;
9 |
10 | import static org.testng.Assert.assertEquals;
11 |
12 | public class NoMockTest {
13 |
14 | @Test
15 | public void testCheckCodeDuplicate1() throws Exception {
16 |
17 | FooImpl foo = new FooImpl();
18 | foo.setBar(new Bar() {
19 | @Override
20 | public Set getAllCodes() {
21 | return Collections.singleton("123");
22 | }
23 | });
24 | assertEquals(foo.checkCodeDuplicate("123"), true);
25 |
26 | }
27 |
28 | @Test
29 | public void testCheckCodeDuplicate2() throws Exception {
30 |
31 | FooImpl foo = new FooImpl();
32 | foo.setBar(new FakeBar(Collections.singleton("123")));
33 | assertEquals(foo.checkCodeDuplicate("123"), true);
34 |
35 | }
36 |
37 | public class FakeBar implements Bar {
38 |
39 | private final Set codes;
40 |
41 | public FakeBar(Set codes) {
42 | this.codes = codes;
43 | }
44 |
45 | @Override
46 | public Set getAllCodes() {
47 | return codes;
48 | }
49 |
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/spring1/Spring_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring1;
2 |
3 | import me.chanjar.common.Bar;
4 | import me.chanjar.common.Foo;
5 | import me.chanjar.common.FooImpl;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.mock.mockito.MockBean;
8 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.TestExecutionListeners;
11 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
12 | import org.testng.annotations.Test;
13 |
14 | import java.util.Collections;
15 |
16 | import static org.mockito.Mockito.when;
17 | import static org.testng.Assert.assertEquals;
18 |
19 | @ContextConfiguration(classes = FooImpl.class)
20 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
21 | public class Spring_1_Test extends AbstractTestNGSpringContextTests {
22 |
23 | @MockBean
24 | private Bar bar;
25 |
26 | @Autowired
27 | private Foo foo;
28 |
29 | @Test
30 | public void testCheckCodeDuplicate() throws Exception {
31 |
32 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
33 | assertEquals(foo.checkCodeDuplicate("123"), true);
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/spring2/Loo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | public interface Loo {
4 | boolean checkCodeDuplicate(String code);
5 | }
6 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/spring2/LooImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | import me.chanjar.common.Foo;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class LooImpl implements Loo {
9 |
10 | private Foo foo;
11 |
12 | @Override
13 | public boolean checkCodeDuplicate(String code) {
14 | return foo.checkCodeDuplicate(code);
15 | }
16 |
17 | @Autowired
18 | public void setFoo(Foo foo) {
19 | this.foo = foo;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/spring2/Spring_2_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | import me.chanjar.common.Bar;
4 | import me.chanjar.common.FooImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.mock.mockito.MockBean;
7 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.TestExecutionListeners;
10 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
11 | import org.testng.annotations.Test;
12 |
13 | import java.util.Collections;
14 |
15 | import static org.mockito.Mockito.when;
16 | import static org.testng.Assert.assertEquals;
17 |
18 | @ContextConfiguration(classes = { FooImpl.class, LooImpl.class })
19 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
20 | public class Spring_2_Test extends AbstractTestNGSpringContextTests {
21 |
22 | @MockBean
23 | private Bar bar;
24 |
25 | @Autowired
26 | private Loo loo;
27 |
28 | @Test
29 | public void testCheckCodeDuplicate() throws Exception {
30 |
31 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
32 | assertEquals(loo.checkCodeDuplicate("123"), true);
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/mock/src/test/java/me/chanjar/springboot1/Boot_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.springboot1;
2 |
3 | import me.chanjar.common.Bar;
4 | import me.chanjar.common.Foo;
5 | import me.chanjar.common.FooImpl;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.boot.test.mock.mockito.MockBean;
9 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
10 | import org.springframework.test.context.TestExecutionListeners;
11 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
12 | import org.testng.annotations.Test;
13 |
14 | import java.util.Collections;
15 |
16 | import static org.mockito.Mockito.when;
17 | import static org.testng.Assert.assertEquals;
18 |
19 | @SpringBootTest(classes = { FooImpl.class })
20 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
21 | public class Boot_1_Test extends AbstractTestNGSpringContextTests {
22 |
23 | @MockBean
24 | private Bar bar;
25 |
26 | @Autowired
27 | private Foo foo;
28 |
29 | @Test
30 | public void testCheckCodeDuplicate() throws Exception {
31 |
32 | when(bar.getAllCodes()).thenReturn(Collections.singleton("123"));
33 | assertEquals(foo.checkCodeDuplicate("123"), true);
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/mvc/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-mvc
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-web
26 |
27 |
28 |
29 | org.slf4j
30 | slf4j-api
31 |
32 |
33 |
34 | ch.qos.logback
35 | logback-classic
36 |
37 |
38 |
39 |
40 | org.testng
41 | testng
42 | test
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-test
48 | test
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.apache.maven.plugins
57 | maven-jar-plugin
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/mvc/src/main/java/me/chanjar/web/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.web;
2 |
3 | public interface Foo {
4 |
5 | boolean checkCodeDuplicate(String code);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/mvc/src/main/java/me/chanjar/web/FooController.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.web;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.http.HttpStatus;
5 | import org.springframework.http.ResponseEntity;
6 | import org.springframework.stereotype.Controller;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RequestMethod;
9 | import org.springframework.web.bind.annotation.RequestParam;
10 |
11 | @Controller
12 | public class FooController {
13 |
14 | @Autowired
15 | private Foo foo;
16 |
17 | @RequestMapping(path = "/foo/check-code-dup", method = RequestMethod.GET)
18 | public ResponseEntity checkCodeDuplicate(@RequestParam String code) {
19 |
20 | return new ResponseEntity<>(
21 | Boolean.valueOf(foo.checkCodeDuplicate(code)),
22 | HttpStatus.OK
23 | );
24 |
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/mvc/src/main/java/me/chanjar/web/FooImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.web;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | @Component
6 | public class FooImpl implements Foo {
7 |
8 | @Override
9 | public boolean checkCodeDuplicate(String code) {
10 | return true;
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/mvc/src/test/java/me/chanjar/spring1/SpringMvc_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring1;
2 |
3 | import me.chanjar.web.FooController;
4 | import me.chanjar.web.FooImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.test.context.ContextConfiguration;
7 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
8 | import org.springframework.test.context.web.WebAppConfiguration;
9 | import org.springframework.test.web.servlet.MockMvc;
10 | import org.springframework.web.context.WebApplicationContext;
11 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
12 | import org.testng.annotations.BeforeMethod;
13 | import org.testng.annotations.Test;
14 |
15 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
16 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
17 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
18 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
19 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
20 |
21 | @EnableWebMvc
22 | @WebAppConfiguration
23 | @ContextConfiguration(classes = { FooController.class, FooImpl.class })
24 | public class SpringMvc_1_Test extends AbstractTestNGSpringContextTests {
25 |
26 | @Autowired
27 | private WebApplicationContext wac;
28 |
29 | private MockMvc mvc;
30 |
31 | @BeforeMethod
32 | public void prepareMockMvc() {
33 | this.mvc = webAppContextSetup(wac).build();
34 | }
35 |
36 | @Test
37 | public void testController() throws Exception {
38 |
39 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
40 | .andDo(print())
41 | .andExpect(status().isOk())
42 | .andExpect(content().string("true"));
43 |
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/mvc/src/test/java/me/chanjar/spring2/SpringMvc_2_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | import me.chanjar.web.Foo;
4 | import me.chanjar.web.FooController;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.mock.mockito.MockBean;
7 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.TestExecutionListeners;
10 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
11 | import org.springframework.test.context.web.WebAppConfiguration;
12 | import org.springframework.test.web.servlet.MockMvc;
13 | import org.springframework.web.context.WebApplicationContext;
14 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
15 | import org.testng.annotations.BeforeMethod;
16 | import org.testng.annotations.Test;
17 |
18 | import static org.mockito.Matchers.anyString;
19 | import static org.mockito.Mockito.when;
20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
21 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
24 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
25 |
26 | @EnableWebMvc
27 | @WebAppConfiguration
28 | @ContextConfiguration(classes = { FooController.class })
29 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
30 | public class SpringMvc_2_Test extends AbstractTestNGSpringContextTests {
31 |
32 | @Autowired
33 | private WebApplicationContext wac;
34 |
35 | @MockBean
36 | private Foo foo;
37 |
38 | private MockMvc mvc;
39 |
40 | @BeforeMethod
41 | public void prepareMockMvc() {
42 | this.mvc = webAppContextSetup(wac).build();
43 | }
44 |
45 | @Test
46 | public void testController() throws Exception {
47 |
48 | when(foo.checkCodeDuplicate(anyString())).thenReturn(true);
49 |
50 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
51 | .andDo(print())
52 | .andExpect(status().isOk())
53 | .andExpect(content().string("true"));
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/mvc/src/test/java/me/chanjar/springboot1/BootMvc_1_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.springboot1;
2 |
3 | import me.chanjar.web.FooController;
4 | import me.chanjar.web.FooImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.springframework.test.web.servlet.MockMvc;
10 | import org.testng.annotations.Test;
11 |
12 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
13 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
14 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
15 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
16 |
17 | @WebMvcTest
18 | @ContextConfiguration(classes = { FooController.class, FooImpl.class })
19 | public class BootMvc_1_Test extends AbstractTestNGSpringContextTests {
20 |
21 | @Autowired
22 | private MockMvc mvc;
23 |
24 | @Test
25 | public void testController() throws Exception {
26 |
27 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
28 | .andDo(print())
29 | .andExpect(status().isOk())
30 | .andExpect(content().string("true"));
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/mvc/src/test/java/me/chanjar/springboot2/BootMvc_2_Test.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.springboot2;
2 |
3 | import me.chanjar.web.Foo;
4 | import me.chanjar.web.FooController;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7 | import org.springframework.boot.test.mock.mockito.MockBean;
8 | import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.TestExecutionListeners;
11 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
12 | import org.springframework.test.web.servlet.MockMvc;
13 | import org.testng.annotations.Test;
14 |
15 | import static org.mockito.Matchers.anyString;
16 | import static org.mockito.Mockito.when;
17 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
18 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
20 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21 |
22 | @WebMvcTest
23 | @ContextConfiguration(classes = { FooController.class })
24 | @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
25 | public class BootMvc_2_Test extends AbstractTestNGSpringContextTests {
26 |
27 | @Autowired
28 | private MockMvc mvc;
29 |
30 | @MockBean
31 | private Foo foo;
32 |
33 | @Test
34 | public void testController() throws Exception {
35 |
36 | when(foo.checkCodeDuplicate(anyString())).thenReturn(true);
37 |
38 | this.mvc.perform(get("/foo/check-code-dup").param("code", "123"))
39 | .andDo(print())
40 | .andExpect(status().isOk())
41 | .andExpect(content().string("true"));
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 | pom
10 |
11 |
12 | basic
13 | annotation
14 | mock
15 | rdbs
16 | rdbs-docker
17 | mvc
18 | configuration
19 | share-config
20 | aop
21 |
22 |
23 |
24 |
25 | 1.8
26 | UTF-8
27 | true
28 | true
29 |
30 | 1.5.4.RELEASE
31 | 1.9.5
32 | 6.8.7
33 | 3.5
34 | 4.1
35 |
36 | 2.6
37 | 2.22.1
38 | 3.3
39 | 0.7.9
40 | 3.2.1
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-dependencies
50 | ${spring-boot.version}
51 | pom
52 | import
53 |
54 |
55 |
56 | org.testng
57 | testng
58 | ${testng.version}
59 |
60 |
61 |
62 | org.apache.commons
63 | commons-lang3
64 | ${commons-lang3.version}
65 |
66 |
67 |
68 | org.apache.commons
69 | commons-collections4
70 | ${commons-collections4.version}
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | false
81 |
82 | central
83 | http://repo.maven.apache.org/maven2
84 |
85 |
86 |
87 | false
88 |
89 | spring-releases
90 | https://repo.spring.io/libs-release
91 |
92 |
93 |
94 |
95 |
96 | spring-releases
97 | https://repo.spring.io/libs-release
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.apache.maven.plugins
105 | maven-compiler-plugin
106 | ${maven.compiler.plugin.version}
107 |
108 | ${java.version}
109 | ${java.version}
110 | ${project.build.sourceEncoding}
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
121 |
122 | org.apache.maven.plugins
123 | maven-jar-plugin
124 | ${maven.jar.plugin.version}
125 |
126 |
127 |
128 | test-jar
129 |
130 |
131 | true
132 |
133 |
134 |
135 |
136 |
137 |
140 |
141 | org.apache.maven.plugins
142 | maven-failsafe-plugin
143 | ${maven.failsafe.plugin.version}
144 |
145 |
146 |
147 | org.flywaydb
148 | flyway-maven-plugin
149 | ${flyway.maven.plugin.version}
150 |
151 | ${skipITs}
152 |
153 |
154 |
155 | clean-db
156 | post-integration-test
157 |
158 |
159 | clean
160 |
161 |
162 |
163 |
164 |
165 |
166 | org.jacoco
167 | jacoco-maven-plugin
168 | ${jacoco.maven.plugin.version}
169 |
170 |
171 |
172 | default-prepare-agent
173 |
174 | prepare-agent
175 |
176 |
177 |
178 | default-prepare-agent-integration
179 |
180 | prepare-agent-integration
181 |
182 |
183 |
184 | default-report
185 | test
186 |
187 | report
188 |
189 |
190 |
191 | default-report-integration
192 | integration-test
193 |
194 | report-integration
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
--------------------------------------------------------------------------------
/rdbs-docker/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-rdbs-docker
13 | jar
14 |
15 |
16 | 0.28.0
17 | 2.22.0
18 | 2.19
19 |
20 |
21 | false
22 |
23 | ${skipTests}
24 |
25 | ${skipTests}
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-jdbc
39 |
40 |
41 |
42 | org.flywaydb
43 | flyway-core
44 |
45 |
46 |
47 | org.slf4j
48 | slf4j-api
49 |
50 |
51 |
52 | ch.qos.logback
53 | logback-classic
54 |
55 |
56 |
57 | mysql
58 | mysql-connector-java
59 | 8.0.12
60 |
61 |
62 |
63 | org.testng
64 | testng
65 | test
66 |
67 |
68 |
69 | org.springframework.boot
70 | spring-boot-starter-test
71 | test
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-maven-plugin
81 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-jar-plugin
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-surefire-plugin
96 | ${maven-surefire-plugin.version}
97 |
98 | ${skipUTs}
99 |
100 |
101 |
102 |
103 | org.apache.maven.plugins
104 | maven-failsafe-plugin
105 | ${maven-failsafe-plugin.version}
106 |
107 |
108 | integration-test
109 |
110 | integration-test
111 |
112 |
113 |
114 | verify
115 |
116 | verify
117 |
118 |
119 |
120 |
121 |
122 | ${skipTests}
123 |
124 | ${skipITs}
125 |
128 |
129 | jdbc:mysql://localhost:${docker-mysql.port}/test
130 | foo
131 | bar
132 |
133 |
134 |
135 |
136 |
137 | io.fabric8
138 | docker-maven-plugin
139 | ${fabric8.dmp.version}
140 |
141 |
142 | ${skipITs}
143 |
144 |
145 |
146 | mysql:8
147 |
148 |
149 |
150 |
152 | docker-mysql.port:3306
153 |
154 |
155 |
156 | 123456
157 | test
158 | foo
159 | bar
160 |
161 |
162 |
163 |
164 | MySQL init process done. Ready for start up.
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | start
176 | pre-integration-test
177 |
178 | start
179 |
180 |
181 |
182 |
183 | stop
184 | post-integration-test
185 |
186 | stop
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/rdbs-docker/src/main/java/me/chanjar/domain/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | public class Foo {
4 |
5 | private String name;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/rdbs-docker/src/main/java/me/chanjar/domain/FooRepository.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | public interface FooRepository {
4 |
5 | void save(Foo foo);
6 |
7 | void delete(String name);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/rdbs-docker/src/main/java/me/chanjar/domain/FooRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.jdbc.core.JdbcTemplate;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public class FooRepositoryImpl implements FooRepository {
9 |
10 | private JdbcTemplate jdbcTemplate;
11 |
12 | @Override
13 | public void save(Foo foo) {
14 | jdbcTemplate.update("INSERT INTO FOO(name) VALUES (?)", foo.getName());
15 | }
16 |
17 | @Override
18 | public void delete(String name) {
19 | jdbcTemplate.update("DELETE FROM FOO WHERE NAME = ?", name);
20 | }
21 |
22 | @Autowired
23 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
24 | this.jdbcTemplate = jdbcTemplate;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/rdbs-docker/src/main/resources/db/migration/V1.0.0__foo-ddl.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE FOO (
2 | name VARCHAR(100)
3 | );
4 |
--------------------------------------------------------------------------------
/rdbs-docker/src/test/java/me/chanjar/domain/FooRepositoryImplIT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | import org.flywaydb.core.Flyway;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.context.EnvironmentAware;
8 | import org.springframework.core.env.Environment;
9 | import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
10 | import org.testng.annotations.AfterTest;
11 | import org.testng.annotations.Test;
12 |
13 | import static org.testng.Assert.*;
14 |
15 | @SpringBootTest(properties = "spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver")
16 | @SpringBootApplication
17 | public class FooRepositoryImplIT extends AbstractTransactionalTestNGSpringContextTests implements EnvironmentAware {
18 |
19 | @Autowired
20 | private FooRepository fooRepository;
21 |
22 | @Autowired
23 | private Flyway flyway;
24 |
25 | @Test
26 | public void testSave() {
27 |
28 | Foo foo = new Foo();
29 | foo.setName("Bob");
30 | fooRepository.save(foo);
31 |
32 | assertEquals(countRowsInTable("FOO"), 1);
33 | countRowsInTableWhere("FOO", "name = 'Bob'");
34 | }
35 |
36 | @Test(dependsOnMethods = "testSave")
37 | public void testDelete() {
38 |
39 | assertEquals(countRowsInTable("FOO"), 0);
40 |
41 | Foo foo = new Foo();
42 | foo.setName("Bob");
43 | fooRepository.save(foo);
44 |
45 | fooRepository.delete(foo.getName());
46 | assertEquals(countRowsInTable("FOO"), 0);
47 |
48 | }
49 |
50 | @AfterTest
51 | public void cleanDb() {
52 | flyway.clean();
53 | }
54 |
55 | @Override
56 | public void setEnvironment(Environment environment) {
57 | System.out.println("===================================");
58 | System.out.println(environment.getProperty("SPRING_DATASOURCE_URL"));
59 | System.out.println("===================================");
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/rdbs-docker/src/test/java/me/chanjar/domain/FooTest.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | import org.testng.annotations.Test;
4 |
5 | public class FooTest {
6 |
7 | @Test
8 | public void testDummy() {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/rdbs/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-rdbs
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | com.h2database
25 | h2
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-jdbc
31 |
32 |
33 |
34 | org.flywaydb
35 | flyway-core
36 |
37 |
38 |
39 | org.slf4j
40 | slf4j-api
41 |
42 |
43 |
44 | ch.qos.logback
45 | logback-classic
46 |
47 |
48 |
49 |
50 | org.testng
51 | testng
52 | test
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-jar-plugin
68 |
69 |
70 | org.apache.maven.plugins
71 | maven-failsafe-plugin
72 |
73 |
74 | integration-test
75 |
76 | integration-test
77 |
78 |
79 |
80 | verify
81 |
82 | verify
83 |
84 |
85 |
86 |
87 |
88 |
98 | ${spring.config.location}
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/rdbs/src/main/java/me/chanjar/domain/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | public class Foo {
4 |
5 | private String name;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/rdbs/src/main/java/me/chanjar/domain/FooRepository.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | public interface FooRepository {
4 |
5 | void save(Foo foo);
6 |
7 | void delete(String name);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/rdbs/src/main/java/me/chanjar/domain/FooRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.domain;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.jdbc.core.JdbcTemplate;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public class FooRepositoryImpl implements FooRepository {
9 |
10 | private JdbcTemplate jdbcTemplate;
11 |
12 | @Override
13 | public void save(Foo foo) {
14 | jdbcTemplate.update("INSERT INTO FOO(name) VALUES (?)", foo.getName());
15 | }
16 |
17 | @Override
18 | public void delete(String name) {
19 | jdbcTemplate.update("DELETE FROM FOO WHERE NAME = ?", name);
20 | }
21 |
22 | @Autowired
23 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
24 | this.jdbcTemplate = jdbcTemplate;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/rdbs/src/main/resources/db/migration/V1.0.0__foo-ddl.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE FOO (
2 | name VARCHAR2(100)
3 | );
4 |
--------------------------------------------------------------------------------
/rdbs/src/main/resources/me/chanjar/domain/foo-ddl.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE FOO (
2 | name VARCHAR2(100)
3 | );
4 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/spring1/Spring_1_IT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring1;
2 |
3 | import me.chanjar.domain.Foo;
4 | import me.chanjar.domain.FooRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.jdbc.core.JdbcTemplate;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
9 | import org.testng.annotations.Test;
10 |
11 | import static org.testng.Assert.assertEquals;
12 |
13 | @ContextConfiguration(classes = Spring_1_IT_Configuration.class)
14 | public class Spring_1_IT extends AbstractTestNGSpringContextTests {
15 |
16 | @Autowired
17 | private FooRepository fooRepository;
18 |
19 | @Autowired
20 | private JdbcTemplate jdbcTemplate;
21 |
22 | @Test
23 | public void testSave() {
24 |
25 | Foo foo = new Foo();
26 | foo.setName("Bob");
27 | fooRepository.save(foo);
28 |
29 | assertEquals(
30 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
31 | Integer.valueOf(1)
32 | );
33 |
34 | }
35 |
36 | @Test(dependsOnMethods = "testSave")
37 | public void testDelete() {
38 |
39 | assertEquals(
40 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
41 | Integer.valueOf(1)
42 | );
43 |
44 | Foo foo = new Foo();
45 | foo.setName("Bob");
46 | fooRepository.save(foo);
47 |
48 | fooRepository.delete(foo.getName());
49 | assertEquals(
50 | jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),
51 | Integer.valueOf(0)
52 | );
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/spring1/Spring_1_IT_Configuration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring1;
2 |
3 | import me.chanjar.domain.FooRepository;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.ComponentScan;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.jdbc.core.JdbcTemplate;
8 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
9 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
10 |
11 | import javax.sql.DataSource;
12 |
13 | @Configuration
14 | @ComponentScan(basePackageClasses = FooRepository.class)
15 | public class Spring_1_IT_Configuration {
16 |
17 | @Bean(destroyMethod = "shutdown")
18 | public DataSource dataSource() {
19 |
20 | return new EmbeddedDatabaseBuilder()
21 | .generateUniqueName(true)
22 | .setType(EmbeddedDatabaseType.H2)
23 | .setScriptEncoding("UTF-8")
24 | .ignoreFailedDrops(true)
25 | .addScript("classpath:me/chanjar/domain/foo-ddl.sql")
26 | .build();
27 | }
28 |
29 | @Bean
30 | public JdbcTemplate jdbcTemplate() {
31 |
32 | return new JdbcTemplate(dataSource());
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/spring1/index.jsp:
--------------------------------------------------------------------------------
1 | Hello world
2 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/spring2/Spring_2_IT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | import me.chanjar.domain.Foo;
4 | import me.chanjar.domain.FooRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.test.context.ContextConfiguration;
7 | import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.testng.Assert.assertEquals;
11 |
12 | @ContextConfiguration(classes = Spring_2_IT_Configuration.class)
13 | public class Spring_2_IT extends AbstractTransactionalTestNGSpringContextTests {
14 |
15 | @Autowired
16 | private FooRepository fooRepository;
17 |
18 | @Test
19 | public void testSave() {
20 |
21 | Foo foo = new Foo();
22 | foo.setName("Bob");
23 | fooRepository.save(foo);
24 |
25 | assertEquals(countRowsInTable("FOO"), 1);
26 | countRowsInTableWhere("FOO", "name = 'Bob'");
27 | }
28 |
29 | @Test(dependsOnMethods = "testSave")
30 | public void testDelete() {
31 |
32 | assertEquals(countRowsInTable("FOO"), 0);
33 |
34 | Foo foo = new Foo();
35 | foo.setName("Bob");
36 | fooRepository.save(foo);
37 |
38 | fooRepository.delete(foo.getName());
39 | assertEquals(countRowsInTable("FOO"), 0);
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/spring2/Spring_2_IT_Configuration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.spring2;
2 |
3 | import me.chanjar.domain.FooRepository;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.ComponentScan;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.jdbc.core.JdbcTemplate;
8 | import org.springframework.jdbc.datasource.DataSourceTransactionManager;
9 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
10 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
11 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
12 | import org.springframework.transaction.PlatformTransactionManager;
13 |
14 | import javax.sql.DataSource;
15 |
16 | @Configuration
17 | @ComponentScan(basePackageClasses = FooRepository.class)
18 | public class Spring_2_IT_Configuration {
19 |
20 | @Bean
21 | public DataSource dataSource() {
22 |
23 | EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
24 | .generateUniqueName(true)
25 | .setType(EmbeddedDatabaseType.H2)
26 | .setScriptEncoding("UTF-8")
27 | .ignoreFailedDrops(true)
28 | .addScript("classpath:me/chanjar/domain/foo-ddl.sql")
29 | .build();
30 | return db;
31 | }
32 |
33 | @Bean
34 | public JdbcTemplate jdbcTemplate() {
35 |
36 | return new JdbcTemplate(dataSource());
37 |
38 | }
39 |
40 | @Bean
41 | public PlatformTransactionManager transactionManager() {
42 | return new DataSourceTransactionManager(dataSource());
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/rdbs/src/test/java/me/chanjar/springboot1/Boot_1_IT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.springboot1;
2 |
3 | import me.chanjar.domain.Foo;
4 | import me.chanjar.domain.FooRepository;
5 | import org.flywaydb.core.Flyway;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.autoconfigure.SpringBootApplication;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
10 | import org.testng.annotations.AfterTest;
11 | import org.testng.annotations.Test;
12 |
13 | import static org.testng.Assert.assertEquals;
14 |
15 | @SpringBootTest
16 | @SpringBootApplication(scanBasePackageClasses = FooRepository.class)
17 | public class Boot_1_IT extends AbstractTransactionalTestNGSpringContextTests {
18 |
19 | @Autowired
20 | private FooRepository fooRepository;
21 |
22 | @Autowired
23 | private Flyway flyway;
24 |
25 | @Test
26 | public void testSave() {
27 |
28 | Foo foo = new Foo();
29 | foo.setName("Bob");
30 | fooRepository.save(foo);
31 |
32 | assertEquals(countRowsInTable("FOO"), 1);
33 | countRowsInTableWhere("FOO", "name = 'Bob'");
34 | }
35 |
36 | @Test(dependsOnMethods = "testSave")
37 | public void testDelete() {
38 |
39 | assertEquals(countRowsInTable("FOO"), 0);
40 |
41 | Foo foo = new Foo();
42 | foo.setName("Bob");
43 | fooRepository.save(foo);
44 |
45 | fooRepository.delete(foo.getName());
46 | assertEquals(countRowsInTable("FOO"), 0);
47 |
48 | }
49 |
50 | @AfterTest
51 | public void cleanDb() {
52 | flyway.clean();
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/share-config/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | me.chanjar
7 | spring-test-examples-aggregator
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | me.chanjar
12 | spring-test-examples-share-config
13 | jar
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-jdbc
26 |
27 |
28 |
29 | org.flywaydb
30 | flyway-core
31 |
32 |
33 |
34 | com.h2database
35 | h2
36 |
37 |
38 |
39 | org.slf4j
40 | slf4j-api
41 |
42 |
43 |
44 | ch.qos.logback
45 | logback-classic
46 |
47 |
48 |
49 |
50 | org.testng
51 | testng
52 | test
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-jar-plugin
68 |
69 |
70 | org.apache.maven.plugins
71 | maven-failsafe-plugin
72 |
73 |
74 | integration-test
75 |
76 | integration-test
77 |
78 |
79 |
80 | verify
81 |
82 | verify
83 |
84 |
85 |
86 |
87 |
88 |
98 | ${spring.config.location}
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/share-config/src/main/java/me/chanjar/shareconfig/config/FooRepositoryConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.config;
2 |
3 | import me.chanjar.shareconfig.service.FooRepository;
4 | import me.chanjar.shareconfig.service.FooRepositoryImpl;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.jdbc.core.JdbcTemplate;
9 |
10 | @Configuration
11 | public class FooRepositoryConfiguration {
12 |
13 | @Autowired
14 | private JdbcTemplate jdbcTemplate;
15 |
16 | @Bean
17 | public FooRepository fooRepository() {
18 | FooRepositoryImpl repository = new FooRepositoryImpl();
19 | repository.setJdbcTemplate(jdbcTemplate);
20 | return repository;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/share-config/src/main/java/me/chanjar/shareconfig/service/Foo.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.service;
2 |
3 | public class Foo {
4 |
5 | private String name;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/share-config/src/main/java/me/chanjar/shareconfig/service/FooRepository.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.service;
2 |
3 | public interface FooRepository {
4 | void save(Foo foo);
5 |
6 | void delete(String name);
7 | }
8 |
--------------------------------------------------------------------------------
/share-config/src/main/java/me/chanjar/shareconfig/service/FooRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.service;
2 |
3 | import org.springframework.jdbc.core.JdbcTemplate;
4 |
5 | public class FooRepositoryImpl implements FooRepository {
6 |
7 | private JdbcTemplate jdbcTemplate;
8 |
9 | @Override
10 | public void save(Foo foo) {
11 | jdbcTemplate.update("INSERT INTO FOO(name) VALUES (?)", foo.getName());
12 | }
13 |
14 | @Override
15 | public void delete(String name) {
16 | jdbcTemplate.update("DELETE FROM FOO WHERE NAME = ?", name);
17 | }
18 |
19 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
20 | this.jdbcTemplate = jdbcTemplate;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/share-config/src/main/resources/db/migration/V1.0.0__foo-ddl.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE FOO (
2 | name VARCHAR2(100)
3 | );
4 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/annotation/FooRepositoryIT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.annotation;
2 |
3 | import me.chanjar.shareconfig.service.FooRepositoryTestBase;
4 | import me.chanjar.shareconfig.testconfig.AnnotationConfiguration;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 |
7 | @SpringBootTest(classes = FooRepositoryIT.class)
8 | @AnnotationConfiguration
9 | public class FooRepositoryIT extends FooRepositoryTestBase {
10 |
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/configuration/FooRepositoryIT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.configuration;
2 |
3 | import me.chanjar.shareconfig.service.FooRepositoryTestBase;
4 | import me.chanjar.shareconfig.testconfig.PlainConfiguration;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 |
7 | @SpringBootTest(classes = PlainConfiguration.class)
8 | public class FooRepositoryIT extends FooRepositoryTestBase {
9 |
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/inter/FooRepositoryIT.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.inter;
2 |
3 | import me.chanjar.shareconfig.service.FooRepositoryTestBase;
4 | import me.chanjar.shareconfig.testconfig.InterfaceConfiguration;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 |
7 | @SpringBootTest(classes = InterfaceConfiguration.class)
8 | public class FooRepositoryIT extends FooRepositoryTestBase {
9 |
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/service/FooRepositoryTestBase.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.service;
2 |
3 | import org.flywaydb.core.Flyway;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
6 | import org.testng.annotations.AfterTest;
7 | import org.testng.annotations.Test;
8 |
9 | import static org.testng.Assert.assertEquals;
10 |
11 | public class FooRepositoryTestBase extends AbstractTransactionalTestNGSpringContextTests {
12 |
13 | @Autowired
14 | private FooRepository fooRepository;
15 |
16 | @Autowired
17 | private Flyway flyway;
18 |
19 | @Test
20 | public void testSave() {
21 |
22 | Foo foo = new Foo();
23 | foo.setName("Bob");
24 | fooRepository.save(foo);
25 |
26 | assertEquals(countRowsInTable("FOO"), 1);
27 | countRowsInTableWhere("FOO", "name = 'Bob'");
28 | }
29 |
30 | @Test(dependsOnMethods = "testSave")
31 | public void testDelete() {
32 |
33 | assertEquals(countRowsInTable("FOO"), 0);
34 |
35 | Foo foo = new Foo();
36 | foo.setName("Bob");
37 | fooRepository.save(foo);
38 |
39 | fooRepository.delete(foo.getName());
40 | assertEquals(countRowsInTable("FOO"), 0);
41 |
42 | }
43 |
44 | @AfterTest
45 | public void cleanDb() {
46 | flyway.clean();
47 | }
48 |
49 | }
50 |
51 |
52 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/testconfig/AnnotationConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.testconfig;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | @Target(ElementType.TYPE)
11 | @Retention(RetentionPolicy.RUNTIME)
12 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
13 | public @interface AnnotationConfiguration {
14 | }
15 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/testconfig/InterfaceConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.testconfig;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
6 | public interface InterfaceConfiguration {
7 | }
8 |
--------------------------------------------------------------------------------
/share-config/src/test/java/me/chanjar/shareconfig/testconfig/PlainConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.chanjar.shareconfig.testconfig;
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication;
4 |
5 | @SpringBootApplication(scanBasePackages = "me.chanjar.shareconfig")
6 | public class PlainConfiguration {
7 | }
8 |
--------------------------------------------------------------------------------