├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── mvpjava │ │ ├── Main.java │ │ ├── mongo │ │ ├── LogController.java │ │ ├── LogRecord.java │ │ ├── LogRepository.java │ │ └── MongoService.java │ │ └── mongoconfig │ │ ├── MongoConfigProfiles.java │ │ ├── MongoProperties.java │ │ └── SystemProfileValueSource2.java └── resources │ ├── application-it-embedded.properties │ ├── application-it.properties │ ├── application-prod.properties │ └── application.properties └── test └── java ├── com └── mvpjava │ └── it │ └── mongo │ ├── embeddedMongo │ ├── MongoSliceIT.java │ ├── MongoSliceWithServiceIT.java │ └── MongoTomcatIT.java │ └── realMongo │ └── RealMongoEmbeddTomcatIT.java └── unit └── UselessUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springboot-IntegrationTests-Tutorial 2 | 3 | Covers how to select and execute different groups/sub-sets of Integration Tests by taking a layered approach. 4 | 5 | The Spring Boot testing tutorial covers how to define and activate different Spring Profiles via annotaions and 6 | property files in order to switch between executing an embedded mongoDB integration test or a real mongoDB database. 7 | 8 | The Project uses Spring Boot Testing 1.5 which allows you to test a slice of you application via the use the @DataMongoTest annotation and also how to perform more broad based integration testing via the use of the @SpringBootTest annotation. 9 | 10 | You can also follow along with my YouTube video Tutorial 11 | https://youtu.be/VeFr1CRFdC4 12 | 13 | You can follow the Blog Post which goes along with this Project on mvpjava.com 14 | http://mvpjava.com/spring-boot-integration-testing/ 15 | 16 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | springbootIntegrationTestsTutorial 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | springbootIntegrationTestsTutorial 12 | Spring Boot Profiles, Environment Tutorial 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.2.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-data-mongodb 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | de.flapdoodle.embed 44 | de.flapdoodle.embed.mongo 45 | test 46 | 47 | 48 | org.springframework 49 | spring-core 50 | jar 51 | 52 | 53 | org.springframework 54 | spring-test 55 | jar 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | it-embedded 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-failsafe-plugin 74 | 75 | 76 | 77 | integration-test 78 | verify 79 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/Main.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Main { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Main.class); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongo/LogController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.mvpjava.mongo; 7 | 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @RestController 15 | public class LogController { 16 | 17 | private final MongoService mongoService; 18 | 19 | public LogController(MongoService mongoService) { 20 | this.mongoService = mongoService; 21 | } 22 | 23 | @RequestMapping(value = "/log", method = RequestMethod.POST) 24 | @ResponseBody 25 | public LogRecord log(@RequestBody LogRecord logRecord) { 26 | LogRecord log = mongoService.log(logRecord); 27 | return log; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongo/LogRecord.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongo; 2 | 3 | import java.util.Date; 4 | import java.util.Objects; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.mongodb.core.mapping.Document; 7 | 8 | /** 9 | * Used in Mapping the Log record from Java Object to Mongo DBObject and back. 10 | */ 11 | @Document 12 | public class LogRecord { 13 | @Id private String id; 14 | private String level; 15 | private Date timestamp; 16 | private String message; 17 | 18 | public LogRecord() { 19 | } 20 | 21 | public LogRecord(String level, String message) { 22 | this.level = level; 23 | this.message = message; 24 | setTimestamp(new Date()); 25 | } 26 | 27 | 28 | public String getId() { 29 | return id; 30 | } 31 | 32 | public void setId(String mongoId) { 33 | this.id = mongoId; 34 | } 35 | 36 | public String getLevel() { 37 | return level; 38 | } 39 | 40 | public void setLevel(String level) { 41 | this.level = level; 42 | } 43 | 44 | public String getMessage() { 45 | return message; 46 | } 47 | 48 | public void setMessage(String message) { 49 | this.message = message; 50 | } 51 | 52 | public Date getTimestamp() { 53 | return timestamp; 54 | } 55 | 56 | public void setTimestamp(Date timestamp) { 57 | this.timestamp = timestamp; 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | int hash = 7; 63 | hash = 23 * hash + Objects.hashCode(this.level); 64 | hash = 23 * hash + Objects.hashCode(this.timestamp); 65 | hash = 23 * hash + Objects.hashCode(this.message); 66 | return hash; 67 | } 68 | 69 | @Override 70 | public boolean equals(Object obj) { 71 | if (this == obj) { 72 | return true; 73 | } 74 | if (obj == null) { 75 | return false; 76 | } 77 | if (getClass() != obj.getClass()) { 78 | return false; 79 | } 80 | final LogRecord other = (LogRecord) obj; 81 | if (!Objects.equals(this.level, other.level)) { 82 | return false; 83 | } 84 | if (!Objects.equals(this.message, other.message)) { 85 | return false; 86 | } 87 | if (!Objects.equals(this.timestamp, other.timestamp)) { 88 | return false; 89 | } 90 | return true; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "LogRecord{" + "id=" + id + ", level=" + level + ", timestamp=" + timestamp + ", message=" + message + '}'; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongo/LogRepository.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongo; 2 | 3 | import org.springframework.data.mongodb.repository.MongoRepository; 4 | 5 | public interface LogRepository extends MongoRepository{ 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongo/MongoService.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongo; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.dao.DataAccessException; 5 | import org.springframework.data.mongodb.core.MongoTemplate; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class MongoService { 10 | 11 | private final MongoTemplate mongoTemplate; 12 | 13 | private final String logsCollectionName = "logs"; 14 | 15 | @Autowired 16 | public MongoService(MongoTemplate mongoTemplate) { 17 | this.mongoTemplate = mongoTemplate; 18 | } 19 | 20 | public LogRecord log(LogRecord logRecord) throws DataAccessException { 21 | mongoTemplate.save(logRecord, logsCollectionName); 22 | return findLogMessageById(logRecord.getId()); 23 | } 24 | 25 | public LogRecord findLogMessageById(String id) { 26 | return mongoTemplate.findById( 27 | id, LogRecord.class, logsCollectionName); 28 | } 29 | 30 | public void removeLogCollection() { 31 | mongoTemplate.dropCollection(logsCollectionName); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongoconfig/MongoConfigProfiles.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongoconfig; 2 | 3 | import com.mongodb.MongoClient; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.data.mongodb.MongoDbFactory; 8 | import org.springframework.data.mongodb.core.MongoTemplate; 9 | import org.springframework.data.mongodb.core.SimpleMongoDbFactory; 10 | 11 | @Configuration 12 | @Profile("!it-embedded") //or else problems when using @EnableAutoConfiguration in Integration ests 13 | public class MongoConfigProfiles { 14 | 15 | private final MongoProperties mongoProperties; 16 | 17 | public MongoConfigProfiles(MongoProperties mongoProperties) { 18 | this.mongoProperties = mongoProperties; 19 | } 20 | 21 | @Bean 22 | public MongoDbFactory mongoDbFactory() throws Exception { 23 | MongoClient mongoClient = new MongoClient(mongoProperties.getHost(), mongoProperties.getPort()); 24 | return new SimpleMongoDbFactory(mongoClient, mongoProperties.getDatabase()); 25 | } 26 | 27 | @Bean 28 | public MongoTemplate mongoTemplate() throws Exception { 29 | MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory()); 30 | return mongoTemplate; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongoconfig/MongoProperties.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongoconfig; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.env.Environment; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class MongoProperties { 9 | 10 | private final Environment environment; 11 | 12 | @Autowired 13 | public MongoProperties(Environment environment) { 14 | this.environment = environment; 15 | } 16 | 17 | public String getDatabase() { 18 | return environment.getProperty("mongodb.database"); 19 | } 20 | 21 | public String getHost() { 22 | return environment.getProperty("mongodb.host"); 23 | } 24 | 25 | public int getPort() { 26 | return environment.getProperty("mongodb.port", Integer.class); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mvpjava/mongoconfig/SystemProfileValueSource2.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.mongoconfig; 2 | 3 | import java.util.Objects; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.test.annotation.ProfileValueSource; 6 | import org.springframework.util.Assert; 7 | import org.springframework.util.StringUtils; 8 | 9 | @Component 10 | public class SystemProfileValueSource2 implements ProfileValueSource { 11 | 12 | @Override 13 | public String get(String key) { 14 | Assert.hasText(key, "'key' must not be empty"); 15 | String springProfiles = System.getProperty(key); 16 | if (Objects.isNull(key) || StringUtils.isEmpty(springProfiles)) { 17 | return "it-embedded"; 18 | } 19 | 20 | return System.getProperty(key); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/application-it-embedded.properties: -------------------------------------------------------------------------------- 1 | # MONGODB (MongoProperties for embedded) 2 | spring.data.mongodb.host=127.0.0.1 3 | spring.data.mongodb.port=0 4 | spring.data.mongodb.database=embeddedDB -------------------------------------------------------------------------------- /src/main/resources/application-it.properties: -------------------------------------------------------------------------------- 1 | ## MONGODB (MongoProperties) 2 | spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration 3 | mongodb.database=testint 4 | mongodb.host=localhost 5 | mongodb.port=27017 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | ## MONGODB (MongoProperties) 2 | spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration 3 | mongodb.database=clients 4 | mongodb.host=172.0.3.1 5 | mongodb.port=27018 6 | #mongodb.password=mvpjavasecret 7 | #mongodb.username=mvpjava -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # If No active profile set, then use this one as the active one 2 | spring.profiles.active=it-embedded -------------------------------------------------------------------------------- /src/test/java/com/mvpjava/it/mongo/embeddedMongo/MongoSliceIT.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.it.mongo.embeddedMongo; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.springframework.core.env.AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME; 5 | 6 | import com.mongodb.DBCollection; 7 | import com.mvpjava.mongo.LogRecord; 8 | import com.mvpjava.mongo.LogRepository; 9 | import com.mvpjava.mongoconfig.SystemProfileValueSource2; 10 | import org.junit.After; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; 16 | import org.springframework.data.mongodb.core.MongoTemplate; 17 | import org.springframework.data.mongodb.core.query.Criteria; 18 | import org.springframework.data.mongodb.core.query.Query; 19 | import org.springframework.test.annotation.IfProfileValue; 20 | import org.springframework.test.annotation.ProfileValueSourceConfiguration; 21 | import org.springframework.test.context.junit4.SpringRunner; 22 | 23 | @ProfileValueSourceConfiguration(value = SystemProfileValueSource2.class) 24 | @IfProfileValue(name = ACTIVE_PROFILES_PROPERTY_NAME, value = "it-embedded") //"spring.profiles.active" 25 | @RunWith(SpringRunner.class) 26 | @DataMongoTest 27 | public class MongoSliceIT { 28 | 29 | String collectionName; 30 | LogRecord logRecToInsert; 31 | 32 | @Autowired 33 | private MongoTemplate mongoTemplate; 34 | 35 | @Autowired 36 | private LogRepository logRepository; 37 | 38 | @Before 39 | public void before() { 40 | collectionName = "logs"; 41 | logRecToInsert = new LogRecord("INFO", "Test Info Log messge"); 42 | } 43 | 44 | @After 45 | public void after() { 46 | mongoTemplate.dropCollection(collectionName); 47 | } 48 | 49 | @Test 50 | public void checkMongoTemplate() { 51 | assertNotNull(mongoTemplate); 52 | DBCollection createdCollection = mongoTemplate.createCollection(collectionName); 53 | assertTrue(mongoTemplate.collectionExists(collectionName)); 54 | } 55 | 56 | @Test 57 | public void checkDocumentAndQuery() { 58 | mongoTemplate.save(logRecToInsert, collectionName); 59 | Query query = new Query(new Criteria() 60 | .andOperator(Criteria.where("level").regex(logRecToInsert.getLevel()), 61 | Criteria.where("message").regex(logRecToInsert.getMessage()))); 62 | 63 | LogRecord retrievedLogRecord = mongoTemplate.findOne(query, LogRecord.class, collectionName); 64 | assertNotNull(retrievedLogRecord); 65 | } 66 | 67 | @Test 68 | public void checkLogRepository() { 69 | assertNotNull(logRepository); 70 | LogRecord savedLogRecord = logRepository.save(logRecToInsert); 71 | assertNotNull(logRepository.findOne(savedLogRecord.getId())); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/mvpjava/it/mongo/embeddedMongo/MongoSliceWithServiceIT.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.it.mongo.embeddedMongo; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.springframework.core.env.AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME; 5 | 6 | import com.mvpjava.mongo.LogRecord; 7 | import com.mvpjava.mongo.MongoService; 8 | import com.mvpjava.mongoconfig.SystemProfileValueSource2; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; 13 | import org.springframework.context.annotation.ComponentScan.Filter; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.test.annotation.IfProfileValue; 16 | import org.springframework.test.annotation.ProfileValueSourceConfiguration; 17 | import org.springframework.test.context.junit4.SpringRunner; 18 | 19 | @ProfileValueSourceConfiguration(value = SystemProfileValueSource2.class) 20 | @IfProfileValue(name = ACTIVE_PROFILES_PROPERTY_NAME, value = "it-embedded") //"spring.profiles.active" 21 | @RunWith(SpringRunner.class) 22 | @DataMongoTest(includeFilters = @Filter(Service.class)) 23 | public class MongoSliceWithServiceIT { 24 | 25 | @Autowired 26 | private MongoService mongoService; 27 | 28 | @Test 29 | public void ensureLoggingWorks() { 30 | LogRecord logRecord = new LogRecord("INFO", "This is a test"); 31 | LogRecord logWithPK = mongoService.log(logRecord); 32 | assertNotNull(logWithPK.getId()); 33 | assertEquals(logRecord.getMessage(), logWithPK.getMessage()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/mvpjava/it/mongo/embeddedMongo/MongoTomcatIT.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.it.mongo.embeddedMongo; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.springframework.boot.test.context.SpringBootTest.*; 5 | import static org.springframework.core.env.AbstractEnvironment.*; 6 | 7 | import com.mvpjava.mongo.LogRecord; 8 | import com.mvpjava.mongoconfig.SystemProfileValueSource2; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.boot.test.web.client.TestRestTemplate; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.test.annotation.IfProfileValue; 17 | import org.springframework.test.annotation.ProfileValueSourceConfiguration; 18 | import org.springframework.test.context.junit4.SpringRunner; 19 | 20 | @ProfileValueSourceConfiguration(value = SystemProfileValueSource2.class) 21 | @IfProfileValue(name = ACTIVE_PROFILES_PROPERTY_NAME, value = "it-embedded") 22 | @RunWith(SpringRunner.class) 23 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 24 | @EnableAutoConfiguration //mongoDB 25 | public class MongoTomcatIT { 26 | 27 | @Autowired 28 | private TestRestTemplate restTemplate; 29 | 30 | @Test 31 | public void ensureLoggingWorks() { 32 | LogRecord logRecord = new LogRecord("INFO", "This is a test"); 33 | ResponseEntity responseEntity = restTemplate.postForEntity( 34 | "/log", logRecord, LogRecord.class); 35 | LogRecord logRecordReturned = responseEntity.getBody(); 36 | 37 | assertNotNull("Should have an PK", logRecordReturned.getId()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/mvpjava/it/mongo/realMongo/RealMongoEmbeddTomcatIT.java: -------------------------------------------------------------------------------- 1 | package com.mvpjava.it.mongo.realMongo; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.springframework.boot.test.context.SpringBootTest.*; 5 | import static org.springframework.core.env.AbstractEnvironment.*; 6 | 7 | import com.mvpjava.mongo.LogRecord; 8 | import com.mvpjava.mongoconfig.SystemProfileValueSource2; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.boot.test.web.client.TestRestTemplate; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.test.annotation.IfProfileValue; 16 | import org.springframework.test.annotation.ProfileValueSourceConfiguration; 17 | import org.springframework.test.context.junit4.SpringRunner; 18 | 19 | @ProfileValueSourceConfiguration(value = SystemProfileValueSource2.class) 20 | @IfProfileValue(name = ACTIVE_PROFILES_PROPERTY_NAME, value = "it") 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 23 | public class RealMongoEmbeddTomcatIT { 24 | @Autowired 25 | private TestRestTemplate restTemplate; 26 | 27 | @Test 28 | public void ensureLoggingWorks() { 29 | LogRecord logRecord = new LogRecord("INFO", "This is a test on real monngoDB"); 30 | ResponseEntity responseEntity = restTemplate.postForEntity( 31 | "/log", logRecord, LogRecord.class); 32 | LogRecord logRecordReturned = responseEntity.getBody(); 33 | 34 | assertNotNull("Should have an PK", logRecordReturned.getId()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/unit/UselessUnitTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package unit; 7 | 8 | import org.junit.Test; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class UselessUnitTest { 12 | 13 | @Test 14 | public void uselessUnitTest() { 15 | assertTrue(true); 16 | } 17 | 18 | } 19 | --------------------------------------------------------------------------------