Saturday, October 10, 2015

Getting started with Gradle

From wikipeia : 
Gradle is a build automation tool that builds upon the concepts of Apache Ant and Apache Maven and introduces a Groovy-based domain-specific language (DSL) instead of the more traditional XML form of declaring the project configuration. Gradle uses a directed acyclic graph ("DAG") to determine the order in which tasks can be run.
Gradle was designed for multi-project builds which can grow to be quite large, and supports incremental builds by intelligently determining which parts of the build tree are up-to-date, so that any task dependent upon those parts will not need to be re-executed.
The initial plugins are primarily focused around JavaGroovy and Scala development and deployment, but more languages and project workflows are on the roadmap.

1. Roadmap. 

Let's create imitation of complex application with several projects and several source directories: 
- we will have 3 different  projects with dependencies one from each others
- we will have different source directories (not only main/java)
- we will have different languages (java and groovy) in our application
- we will have source directory with integration tests, which we will be able to run separately from building application

2. Application structure.

For imitation of complex application I created 3 sub-projects : COMMON(empty now), API(I created just one interface here), APP(application itself - implementation of interface declared in API sub-project). 
inside APP sub-project, also for imitation of complex application, inside SRC directory, beside standard source directories(src/main and src/test) I created in addition directories : src/it(integration testing) and src/run(just main class to run application).
That is because I don't want integration tests to be running with unit tests so UNIT and INTEGRATION tests are in different directories : unit tests in standard "test", integration tests - in "it"  directory.
Also I decided to split code by language, so test in java are in directory "test/java", tests in groovy in "test/groovy". 
Full application structure : 



Structure of app sub-project:



3. main project files 

If we have different projects - we need settings.gradle file with just 1 line :

include ":api", ":common", ":app"
 
 
to inform gradle to look also into listed directories.

Also, of course, we need a main project file - build.gradle :

allprojects {
  task hello << { task -> println "I'm $task.project.name" }
}

subprojects {
  apply plugin: "java"  apply plugin: "groovy"
  repositories {
        jcenter()
   }

}

project(':common') { 
  dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.1'    compile "org.spockframework:spock-core:1.0-groovy-2.4"    compile "junit:junit:4.10"  }
} 

project(':api') { 
   dependencies {
      compile project(':common')
   }
} 

project(':app') {

    apply plugin:'application'    mainClassName = "App"
   dependencies {
      compile project(':api')
   }
   
    sourceSets {

        main {
            java {
                srcDirs=['src/main/java', 'src/run/java']
            }
        }

        integTest {
            groovy {
                srcDirs=['src/it/groovy']
            }
            compileClasspath = sourceSets.main.output + configurations.testRuntime
            runtimeClasspath = output + sourceSets.main.output + configurations.testRuntime
        }
    }
    
    task integTest(type: Test, dependsOn:test) {
        testClassesDir = sourceSets.integTest.output.classesDir
        classpath = sourceSets.integTest.runtimeClasspath
    }


}
Here I defined dependencies : "common" - main project, "api" - depend on common,  "app" - depend on api. All external dependencies (junit, spock ....) are defined in "common" sub-project and will be available for all dependend projects ("api" and "app").
  After applying plugins "java" and "groovy" gradle will automatically search for sources in directories "main/java", "main/groovy", "test/java", "test/groovy". To add also "main/run" - I had to "extend" current value of main source set : to add additional directory to it :
main {
    java {
        srcDirs=['src/main/java', 'src/run/java']
    }
}
 
Integration test - it's a independent source directory, so I have to define it : 
integTest {
    groovy {
        srcDirs=['src/it/groovy']
    }
    compileClasspath = sourceSets.main.output + configurations.testRuntime
    runtimeClasspath = output + sourceSets.main.output + configurations.testRuntime
} 

4. Api project - test interface

As I mentioned before, in api project I placed just one interface : 

package com.demien.gradletest;

public interface TestProcessor {
    String getGreetingWord();
}

5. App project - interface implementations

In App project I created 2 different implementations of test interface :

package com.demien.gradletest;
public class TestHelloProcessor implements TestProcessor {
    @Override    public String getGreetingWord() {
        return "Hello";
    }
}


package com.demien.gradletest;
public class TestHiProcessor implements TestProcessor {

    @Override    public String getGreetingWord() {
        return "Hi";
    }
}

6. App project - test class

Purpose of test class - just to be used in test. So it use implementation of interface to create greeting string : 
package com.demien.gradletest;

public class TestClass {

    TestProcessor testProcessor;

    public void setTestProcessor(TestProcessor testProcessor) {
        this.testProcessor = testProcessor;
    }

    public String greeting(String name) {
        return testProcessor.getGreetingWord() +", "+name;
    }
}

7. App project - run file

Of cource it's pointless and stupid - to create different source directory for app run class. 
It was made just learning work with source directories in Gradle :) 
So app/run/java/app.java class : 
import com.demien.gradletest.TestClass;
import com.demien.gradletest.TestHelloProcessor;
import com.demien.gradletest.TestHiProcessor;
import com.demien.gradletest.TestProcessor;


public class App {
    public static void main(String[] args) {
        TestProcessor testHelloProcessor=new TestHelloProcessor();
        TestProcessor testHiProcessor=new TestHiProcessor();
        TestClass testClass=new TestClass();

        testClass.setTestProcessor(testHelloProcessor);
        System.out.println(testClass.greeting("Joe"));


        testClass.setTestProcessor(testHiProcessor);
        System.out.println(testClass.greeting("Anna"));
    }
}

Result of execution : 
Hello, Joe
Hi, Anna

8. App - unit tests

Unit tests have to test application by not real objects, but just mocks. 
I implemented one mock test in groovy test : 

/app/test/java
 
package com.demien.gradletest
import spock.lang.Specification
class GroovySpockClassTest extends Specification {

    def "Just say hello"() {
        System.out.println("Hello from groovy JUnit test class")
    }

    def "Unit test with mocked method, should return HOW ARE YOU, JOE"() {
        setup :
        TestProcessor mock=Mock()
        mock.getGreetingWord()>>"How are you"        TestClass testClass=new TestClass(testProcessor: mock)

        when:
        String result=testClass.greeting("Joe")

        then:
        result=="How are you, Joe"    }
}

JUnit has no abilities for working with mocks - it's additional libraries like "mockito" 
so JUnit test is "empty" :)  
- it's anoter pointless things - it's also just for using tests in different languages :)
/app/tests/java
package com.demien.gradletest;

import org.junit.Assert;
import org.junit.Test;

public class JavaJunitTestClass {

    @Test    public void itHaveToBeTest() {
        Assert.assertTrue(true);
        System.out.println("Hello from java JUnit test class");
    }
}

9. App - integration test

Integration test have to test application not by mocks(like in unit tests) but by real objects.
So I created 2 tests for testing both implementations of test interface:
 
package com.demien.gradletest
import spock.lang.Specification
class IntegrationTest extends Specification {

    def "Main integration test with REAL HELLO PROCESSOR should return HELLO, JOE"() {

        setup :
        TestProcessor processor=new TestHelloProcessor()
        TestClass testClass=new TestClass(testProcessor: processor)

        when:
        String result=testClass.greeting("Joe")

        then:
        result=="Hello, Joe"    }

    def "Main integration test with REAL HI PROCESSOR should return HI, JOE"() {

        setup :
        TestProcessor processor=new TestHiProcessor()
        TestClass testClass=new TestClass(testProcessor: processor)

        when:
        String result=testClass.greeting("Joe")

        then:
        result=="Hi, Joe"    }


}

10. The end 

Application development is completed. 
We have several sub-projects, different directories for java and groovy and few additional source directories. 
Also, with the help of gradle we now can run integration tests by executing different gradle ask : 


Full source code can be downloaded from here. 

Thursday, October 8, 2015

Spring data simple example

1.intro

Very often, on DB level there are a lot of classes(DAOs) with similar methods:

To avoid that  - there are  lot of different strategies. In my blog a described some of them : 1. using genericDao    2. EasyJDBC tool
Spring Data - another approach  : you just  have to create an interface (which can be extended from  default CRUD repository) and leave it without implementation. String will generate implementation for you!

2.project structure

Everything is pretty simple : one entity (Category), one dao-repository(CategoryRepository) interface, one config class for spring and application runner(class with main procedure):



3. project pom.xml

Just 3 dependencies here :  spring data, persistence api for annotation support, H2 database.
 
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demien</groupId>
    <artifactId>sdata</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.3.4.RELEASE</version>
    </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.5.Final</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.173</version>
        </dependency>

    </dependencies>

</project>

4. app.properties

Properties for H2 DB and hibernate
 
#DB properties:db.driver=org.h2.Driverdb.url=jdbc:h2:~/testdb.username=sadb.password=sa
#Hibernate Configuration:db.hibernate.dialect=org.hibernate.dialect.H2Dialectdb.hibernate.show_sql=falsedb.entitymanager.packages.to.scan=com.demien.sdata.domaindb.hibernate.hbm2ddl.auto = create

 

5. test entity

It's a very simple entity with persistence api annotations. 

package com.demien.sdata.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity(name = "CATEGORY")
public class Category {

    @Id    @Column(name = "CATEGORY_ID")
    private Long categoryId;

    @Column(name="CATEGORY_NAME")
    private String categoryName;

    @Column(name = "CATEGORY_DESCRIPTION")
    private String categoryDescription;

    @Column(name="PARENT_CATEGORY_ID")
    private Long parentCategoryId;

    public Category() {}

    public Long getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Long categoryId) {
        this.categoryId = categoryId;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public String getCategoryDescription() {
        return categoryDescription;
    }

    public void setCategoryDescription(String categoryDescription) {
        this.categoryDescription = categoryDescription;
    }

    public Long getParentCategoryId() {
        return parentCategoryId;
    }

    public void setParentCategoryId(Long parentCategoryId) {
        this.parentCategoryId = parentCategoryId;
    }

    @Override    public String toString() {
        return "Category{" +
                "categoryId=" + categoryId +
                ", categoryName='" + categoryName + '\'' +
                '}';
    }
}

6. repository

As I mention before, we just have to create interface - implementation will be created by Spring. Interface extended from JpaRepository - it has definition of all base db methods (like save, find, delete...). I added only one custom method to interface, and again : it's just a method without implementation. 


package com.demien.sdata.repository;

import com.demien.sdata.domain.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository(value = "CategoryRepository")
public interface CategoryRepository extends JpaRepository<Category, Long> {

    @Query("FROM CATEGORY where CATEGORY_NAME like %?1% ")
    List<Category> findByPattern(String pattern);
}

7. spring config

XML configs are not very popular at modern time, so I used XML-less Spring configuration. 

package com.demien.sdata;

import org.hibernate.ejb.HibernatePersistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;

@Configuration@EnableTransactionManagement@ComponentScan("com.demien.sdata")
@PropertySource("classpath:app.properties")
@EnableJpaRepositories("com.demien.sdata.repository")
public class AppConfig {


private static final String PROP_DATABASE_DRIVER = "db.driver";
private static final String PROP_DATABASE_PASSWORD = "db.password";
private static final String PROP_DATABASE_URL = "db.url";
private static final String PROP_DATABASE_USERNAME = "db.username";
private static final String PROP_HIBERNATE_DIALECT = "db.hibernate.dialect";
private static final String PROP_HIBERNATE_SHOW_SQL = "db.hibernate.show_sql";
private static final String PROP_ENTITYMANAGER_PACKAGES_TO_SCAN = "db.entitymanager.packages.to.scan";
private static final String PROP_HIBERNATE_HBM2DDL_AUTO = "db.hibernate.hbm2ddl.auto";

@Resourceprivate Environment env;

    @Bean    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(env.getRequiredProperty(PROP_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROP_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROP_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROP_DATABASE_PASSWORD));

        return dataSource;
    }

    @Bean    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
        entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROP_ENTITYMANAGER_PACKAGES_TO_SCAN));

        entityManagerFactoryBean.setJpaProperties(getHibernateProperties());

        return entityManagerFactoryBean;
    }

    @Bean    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());

        return transactionManager;
    }

    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getRequiredProperty(PROP_HIBERNATE_DIALECT));
        properties.put("hibernate.show_sql", env.getRequiredProperty(PROP_HIBERNATE_SHOW_SQL));
        properties.put("hibernate.hbm2ddl.auto", env.getRequiredProperty(PROP_HIBERNATE_HBM2DDL_AUTO));

        return properties;
    }
}
 

8. main runner

I'm starting Spring context and testing main  repository methods here

package com.demien.sdata;

import com.demien.sdata.domain.Category;
import com.demien.sdata.repository.CategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

/** * Created by dmitry on 05.10.15. */public class App {




    private static ApplicationContext applicationContext;
    public static void main(String args[]) {
        applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
        new App().test();
    }

    public void test() {
        CategoryRepository categoryRepository=(CategoryRepository)applicationContext.getBean("CategoryRepository");

        Category  category=new Category();
        category.setCategoryId(1l);
        category.setCategoryName("Test 1");
        categoryRepository.save(category);

        category=new Category();
        category.setCategoryId(2l);
        category.setCategoryName("Test 2");

        categoryRepository.save(category);

        System.out.println("\n categoryRepository.findAll()");
        System.out.println(Arrays.toString(categoryRepository.findAll().toArray()));

        System.out.println("\n categoryRepository.findOne(1l)");
        System.out.println(categoryRepository.findOne(1l));


        System.out.println("\n categoryRepository.findByPattern(2)");
        System.out.println(Arrays.toString(categoryRepository.findByPattern("2").toArray()));


        category.setCategoryName("new name");
        categoryRepository.save(category);
        System.out.println("\n UPDATE to new name for element with id=2");
        System.out.println(Arrays.toString(categoryRepository.findAll().toArray()));

        categoryRepository.delete(category);
        System.out.println("\n DELETE of element with id=2");
        System.out.println(Arrays.toString(categoryRepository.findAll().toArray()));


    }
}

9. results 

Everything is working as expected:


 categoryRepository.findAll()
[Category{categoryId=1, categoryName='Test 1'}, Category{categoryId=2, categoryName='Test 2'}]

 categoryRepository.findOne(1l)
Category{categoryId=1, categoryName='Test 1'}

 categoryRepository.findByPattern(2)
[Category{categoryId=2, categoryName='Test 2'}]

 UPDATE to new name for element with id=2
[Category{categoryId=1, categoryName='Test 1'}, Category{categoryId=2, categoryName='new name'}]

 DELETE of element with id=2
[Category{categoryId=1, categoryName='Test 1'}]

Process finished with exit code 0


10. the end

Spring data - very good option to be used on DAO level of application.
Full source code can be downloaded from here.

Saturday, October 3, 2015

Spring boot - simple example

1. Intro

Of course, it's very easy to create rest-web application in java : there are a lot of frameworks and libraries for that, for example Spring MVC, Apache CXF, etc.
But how to test created application ? First of all, you have to build .war file. After that - deploy it to Tomcat. Ok, now application is running, but again : how to test rest services ?  I, for example created for that tool which is using apache.http.client to call rest services. Also I created tool for starting(and testing) application using embedded-jetty, without deploing it to tomcat. And I think, a lot of developers have have such tools.

Spring boot - created to make starting of application and it testing very east out-of-the-box: http://projects.spring.io/spring-boot/


2. Project structure

Project can be generated using online constructor : http://start.spring.io/
 
I created simple project with just one rest-controller, one repository for emulating working with DB, one domain object and one test class. Project was generated by online constructor, I just added new files, renamed main "run" file to App and removed test file.



3. pom.xml

It also was generated by constructor, I just added one more dependency (com.jayway.jsonpath).

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.demien</groupId>
   <artifactId>sboot</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.2.6.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>com.jayway.jsonpath</groupId>
         <artifactId>json-path</artifactId>
         <scope>test</scope>
      </dependency>

   </dependencies>
   
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
   

</project>



4. Entity

Very simple entity class with just 2 fields.
package com.demien.sboot;

public class TestEntity {
    private Integer entityId;
    private String entityName;

    public TestEntity() {}

    public Integer getEntityId() {
        return entityId;
    }

    public void setEntityId(Integer entityId) {
        this.entityId = entityId;
    }

    public String getEntityName() {
        return entityName;
    }

    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }
}

5. Repository 

- simulation of DB repository. I used static ArrayList for storing elements of TestEntity type. And only 3 operations was implemented : add, getById and getAll.

package com.demien.sboot;

import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;


@Componentpublic class TestRepository {
    private static List<TestEntity> storage=new ArrayList<TestEntity>();


    public TestEntity add(TestEntity entity) {
        entity.setEntityId(storage.size()+1);
        storage.add(entity);
        return entity;
    }

    public TestEntity getById(Long entityId) {
        return storage.get(  entityId.intValue()-1);
    }

    public int getMaxId(){
        return storage.size();
    }

    public List<TestEntity> getAll() {
        return storage;
    }



}

6. Controller

Creation of rest-controller is not very hard : just few annotations and calls of repository's methods. 

package com.demien.sboot;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController@RequestMapping("/entity")
public class TestController {

    @Autowired    TestRepository repository;

    @RequestMapping("/hello")
    public String sayHello() {
        return "Hello, world!";
    }

    @RequestMapping(value = "add",  method = RequestMethod.POST)
    public @ResponseBody    TestEntity add(@RequestBody TestEntity entity) {
        TestEntity result=repository.add(entity);
        return result;
    }

    @RequestMapping(value="get/{entityId}", method = RequestMethod.GET)
    public TestEntity get(@PathVariable Long entityId) {
        return repository.getById(entityId);
    }

    @RequestMapping(value="getall", method = RequestMethod.GET)
    public List<TestEntity> getAll() {
        return repository.getAll();
    }

}


7. Application main(starter) file

This file was generated by constructor, I just renamed it. Just after creation of controller we can run App file and it will run our application on embedded-tomcat. And we can test our application by opening in browser URL: http://localhost:8080/entity/hello - it should return "Hello, world!"

As you can see - running of application is VERY easy. It even can be packed into jar file and running using java -jar ...... without tomcat!

package com.demien.sboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplicationpublic class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

8. Test of our controller

Test class class of our controller, from the first look, seems to be complicated - that it just because it has some logic related with json-transformations and some init lines of code for mockMvc. In real life all stuff like this, can be placed in parent test-base-class.
   Logic related with testing itself(methods with @Test annotation) - is very simple and clear.

package com.demien.sboot;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.hasSize;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
@WebAppConfigurationpublic class TestControllerTest {

    private MockMvc mockMvc;

    @Autowired    TestRepository repository;


    private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(),
            Charset.forName("utf8"));

    private HttpMessageConverter mappingJackson2HttpMessageConverter;

    @Autowired    void setConverters(HttpMessageConverter<?>[] converters) {

        this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter(
                hmc -> hmc instanceof MappingJackson2HttpMessageConverter).findAny().get();

        Assert.assertNotNull("the JSON message converter must not be null",
                this.mappingJackson2HttpMessageConverter);
    }

    @Autowired    private WebApplicationContext webApplicationContext;

    protected String json(Object o) throws IOException {
        MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
        this.mappingJackson2HttpMessageConverter.write(o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
        return mockHttpOutputMessage.getBodyAsString();
    }

    @Before    public void init()  {
        this.mockMvc = webAppContextSetup(webApplicationContext).build();
    }

    @Test    public void helloTest() throws Exception {
        mockMvc.perform(get("/entity/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello, world!"));
    }

    @Test    public void addTest() throws Exception {
        TestEntity entity=new TestEntity();
        entity.setEntityName("Test");

        mockMvc.perform(post("/entity/add/")
                .content(this.json(entity))
                .contentType(contentType))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.entityId", is(repository.getMaxId())))
                .andExpect(jsonPath("$.entityName", is(entity.getEntityName())))
        ;
    }

    @Test    public void getTest() throws Exception {
        TestEntity entity=new TestEntity();
        entity.setEntityName("TestGet");
        entity=repository.add(entity);

        mockMvc.perform(get("/entity/get/" + entity.getEntityId()))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.entityId", is(entity.getEntityId())))
                .andExpect(jsonPath("$.entityName", is(entity.getEntityName())))
        ;

    }

    @Test    public void getAllTest() throws Exception {
        TestEntity entity=new TestEntity();
        entity.setEntityName("TestGetAll");
        entity=repository.add(entity);

        mockMvc.perform(get("/entity/getall"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$", hasSize(repository.getAll().size())))
        ;

    }
}
 

9. The end

Spring boot helped us to create rest application with can be run very easy. And also this application is very easy for testing. Full source code can be downloaded from here.