SpringBoot2 สร้าง CRUD RESTful API พร้อม UnitTest แบบรวดเร็ว

Sharing is caring!

Web Service แบบ RESTful protocol ได้รับความนิยมเป็นอย่างมากในปัจจุบัน หลายภาษามี web framework ของตัวอย่าง Java Spring Framework ก็เช่นกัน

SpringBoot เป็น Framework ที่ได้รับความนิยมมากกับ Java เพราะด้วยความง่ายที่เป็นสิ่งที่ถูกพัฒนาเพื่อแก้ปัญหาในการ Setup Project ที่ค่อนข้างยุ่งยากและซับซ้อนในการ Build RESTful API ขึ้นมาใช้งาน Springboot จึงได้รับความนิยมและได้เปรียบเรื่องความรวดเร็วในการ Setup Project

สิ่งที่จะได้รับเมื่ออ่านบทความบทนี้จบ

  • Create Springboot Project
  • CRUD Data with H2 Database
  • Use GET,POST,PUT,DELETE Methods
  • Content-Type : “application/json”
  • MockMvc
  • CrudRepository Interface crud



เริ่มกันเลย

  1. init project https://start.spring.io/
    1. 1
  2. เพิ่ม h2database ในไฟล์ pom.xml
    1. Plain text
      Copy to clipboard
      Open code in new window
      EnlighterJS 3 Syntax Highlighter
      <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.poolsawat</groupId>
      <artifactId>MediumTestRestful</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>MediumTestRestful</name>
      <url>http://maven.apache.org</url>
      <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <java.version>1.8</java.version>
      </properties>
      <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.5.RELEASE</version>
      </parent>
      <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>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      </dependency>
      </dependencies>
      <profiles>
      <profile>
      <id>DEV</id>
      <build>
      <plugins>
      <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      </plugins>
      </build>
      </profile>
      <profile>
      <id>TEST</id>
      <build>
      <plugins>
      <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.15</version><!--$NO-MVN-MAN-VER$ -->
      </plugin>
      </plugins>
      </build>
      </profile>
      </profiles>
      </project>
      <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.poolsawat</groupId> <artifactId>MediumTestRestful</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>MediumTestRestful</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> </parent> <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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies> <profiles> <profile> <id>DEV</id> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </profile> <profile> <id>TEST</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.15</version><!--$NO-MVN-MAN-VER$ --> </plugin> </plugins> </build> </profile> </profiles> </project>
      <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.poolsawat</groupId>
        <artifactId>MediumTestRestful</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
      
        <name>MediumTestRestful</name>
        <url>http://maven.apache.org</url>
      
        <properties>
          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          <java.version>1.8</java.version>
        </properties>
      
        <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.0.5.RELEASE</version>
        </parent>
      
      
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
          </dependency>
          <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
          </dependency>
        </dependencies>
      
      
        <profiles>
          <profile>
            <id>DEV</id>
            <build>
              <plugins>
                <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
              </plugins>
            </build>
          </profile>
          <profile>
            <id>TEST</id>
            <build>
              <plugins>
                <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-surefire-plugin</artifactId>
                  <version>2.15</version><!--$NO-MVN-MAN-VER$ -->
                </plugin>
              </plugins>
            </build>
          </profile>
      
        </profiles>
      
      </project>
      
  3. สร้าง Project Structure ตามนี้
    1. ไฟล์ CrudController.java
      1. Plain text
        Copy to clipboard
        Open code in new window
        EnlighterJS 3 Syntax Highlighter
        package com.poolsawat.medium.testrestful.controller;
        import java.util.Optional;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.DeleteMapping;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.PathVariable;
        import org.springframework.web.bind.annotation.PostMapping;
        import org.springframework.web.bind.annotation.PutMapping;
        import org.springframework.web.bind.annotation.RequestBody;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.ResponseBody;
        import com.poolsawat.medium.testrestful.entity.Blog;
        import com.poolsawat.medium.testrestful.repository.BlogRepository;
        @Controller
        public class CrudController {
        @Autowired
        private BlogRepository blogRepository;
        @RequestMapping("/")
        public @ResponseBody String greeting() {
        return "Hello World";
        }
        @GetMapping("/get")
        public @ResponseBody Iterable<Blog> getBlogs(){
        return this.blogRepository.findAll();
        }
        @GetMapping("/get/id/{id}")
        public @ResponseBody Optional<Blog> getBlog(@PathVariable(name="id") Long id){
        return this.blogRepository.findById(id);
        }
        @PostMapping("/save")
        public @ResponseBody Blog saveBlog(@RequestBody Blog blog){
        return this.blogRepository.save(blog);
        }
        @PutMapping("/update")
        public @ResponseBody Blog updateBlog(@RequestBody Blog blog){
        return this.blogRepository.save(blog);
        }
        @DeleteMapping("/id/{id}")
        public @ResponseBody Long deleteBlog(@PathVariable(name="id") Long id) {
        this.blogRepository.deleteById(id);
        return id;
        }
        }
        package com.poolsawat.medium.testrestful.controller; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.poolsawat.medium.testrestful.entity.Blog; import com.poolsawat.medium.testrestful.repository.BlogRepository; @Controller public class CrudController { @Autowired private BlogRepository blogRepository; @RequestMapping("/") public @ResponseBody String greeting() { return "Hello World"; } @GetMapping("/get") public @ResponseBody Iterable<Blog> getBlogs(){ return this.blogRepository.findAll(); } @GetMapping("/get/id/{id}") public @ResponseBody Optional<Blog> getBlog(@PathVariable(name="id") Long id){ return this.blogRepository.findById(id); } @PostMapping("/save") public @ResponseBody Blog saveBlog(@RequestBody Blog blog){ return this.blogRepository.save(blog); } @PutMapping("/update") public @ResponseBody Blog updateBlog(@RequestBody Blog blog){ return this.blogRepository.save(blog); } @DeleteMapping("/id/{id}") public @ResponseBody Long deleteBlog(@PathVariable(name="id") Long id) { this.blogRepository.deleteById(id); return id; } }
        package com.poolsawat.medium.testrestful.controller;
        
        import java.util.Optional;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.DeleteMapping;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.PathVariable;
        import org.springframework.web.bind.annotation.PostMapping;
        import org.springframework.web.bind.annotation.PutMapping;
        import org.springframework.web.bind.annotation.RequestBody;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.ResponseBody;
        
        import com.poolsawat.medium.testrestful.entity.Blog;
        import com.poolsawat.medium.testrestful.repository.BlogRepository;
        
        @Controller
        public class CrudController {
          
          @Autowired
          private BlogRepository blogRepository;
          
          
          @RequestMapping("/")
            public @ResponseBody String greeting() {
                return "Hello World";
            }
          
          @GetMapping("/get")
          public @ResponseBody Iterable<Blog> getBlogs(){
            return this.blogRepository.findAll();
          }
          
          @GetMapping("/get/id/{id}")
          public @ResponseBody Optional<Blog> getBlog(@PathVariable(name="id") Long id){
            return this.blogRepository.findById(id);
          }
          
          @PostMapping("/save")
          public @ResponseBody Blog saveBlog(@RequestBody Blog blog){
            return this.blogRepository.save(blog);
          }
          
          @PutMapping("/update")
          public @ResponseBody Blog updateBlog(@RequestBody Blog blog){		
            return this.blogRepository.save(blog);
          }
          
          @DeleteMapping("/id/{id}")
          public @ResponseBody Long deleteBlog(@PathVariable(name="id") Long id) {
            this.blogRepository.deleteById(id);
            return id;
          }
          
        }
        



    2. ไฟล์ Blog.java
      1. Plain text
        Copy to clipboard
        Open code in new window
        EnlighterJS 3 Syntax Highlighter
        package com.poolsawat.medium.testrestful.entity;
        import java.io.Serializable;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        @Entity
        public class Blog implements Serializable{
        /**
        *
        */
        private static final long serialVersionUID = 6833355522200232153L;
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String title;
        private String content;
        private String author;
        public Blog() {
        super();
        // TODO Auto-generated constructor stub
        }
        public Blog(Long id, String title, String content, String author) {
        super();
        this.id = id;
        this.title = title;
        this.content = content;
        this.author = author;
        }
        public Long getId() {
        return id;
        }
        public void setId(Long id) {
        this.id = id;
        }
        public String getTitle() {
        return title;
        }
        public void setTitle(String title) {
        this.title = title;
        }
        public String getContent() {
        return content;
        }
        public void setContent(String content) {
        this.content = content;
        }
        public String getAuthor() {
        return author;
        }
        public void setAuthor(String author) {
        this.author = author;
        }
        @Override
        public String toString() {
        return "Blog [id=" + id + ", title=" + title + ", content=" + content + ", author=" + author + "]";
        }
        }
        package com.poolsawat.medium.testrestful.entity; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Blog implements Serializable{ /** * */ private static final long serialVersionUID = 6833355522200232153L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; private String content; private String author; public Blog() { super(); // TODO Auto-generated constructor stub } public Blog(Long id, String title, String content, String author) { super(); this.id = id; this.title = title; this.content = content; this.author = author; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } @Override public String toString() { return "Blog [id=" + id + ", title=" + title + ", content=" + content + ", author=" + author + "]"; } }
        package com.poolsawat.medium.testrestful.entity;
        
        import java.io.Serializable;
        
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        
        @Entity
        public class Blog implements Serializable{
          /**
           * 
           */
          private static final long serialVersionUID = 6833355522200232153L;
        
        
          @Id
          @GeneratedValue(strategy = GenerationType.AUTO)
          private Long id;
            
          private String title;
          
          private String content;
          
          private String author;
          
        
          public Blog() {
            super();
            // TODO Auto-generated constructor stub
          }
        
          public Blog(Long id, String title, String content, String author) {
            super();
            this.id = id;
            this.title = title;
            this.content = content;
            this.author = author;
          }
        
          public Long getId() {
            return id;
          }
        
          public void setId(Long id) {
            this.id = id;
          }
        
          public String getTitle() {
            return title;
          }
        
          public void setTitle(String title) {
            this.title = title;
          }
        
          public String getContent() {
            return content;
          }
        
          public void setContent(String content) {
            this.content = content;
          }
        
          public String getAuthor() {
            return author;
          }
        
          public void setAuthor(String author) {
            this.author = author;
          }
        
          @Override
          public String toString() {
            return "Blog [id=" + id + ", title=" + title + ", content=" + content + ", author=" + author + "]";
          }
          
          
        }
        
    3. ไฟล์ BlogRepository.java
      1. Plain text
        Copy to clipboard
        Open code in new window
        EnlighterJS 3 Syntax Highlighter
        package com.poolsawat.medium.testrestful.repository;
        import java.util.List;
        import org.springframework.data.repository.CrudRepository;
        import org.springframework.stereotype.Repository;
        import com.poolsawat.medium.testrestful.entity.Blog;
        @Repository
        public interface BlogRepository extends CrudRepository<Blog, Long> {
        List<Blog> findByTitle(String title) throws Exception;
        List<Blog> findByAuthor(String author) throws Exception;
        }
        package com.poolsawat.medium.testrestful.repository; import java.util.List; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.poolsawat.medium.testrestful.entity.Blog; @Repository public interface BlogRepository extends CrudRepository<Blog, Long> { List<Blog> findByTitle(String title) throws Exception; List<Blog> findByAuthor(String author) throws Exception; }
        package com.poolsawat.medium.testrestful.repository;
        
        import java.util.List;
        
        import org.springframework.data.repository.CrudRepository;
        import org.springframework.stereotype.Repository;
        
        import com.poolsawat.medium.testrestful.entity.Blog;
        
        @Repository
        public interface BlogRepository extends CrudRepository<Blog, Long> {	
          List<Blog> findByTitle(String title) throws Exception;
          List<Blog> findByAuthor(String author) throws Exception;
        }
        
    4. ไฟล์ Application.java
      1. Plain text
        Copy to clipboard
        Open code in new window
        EnlighterJS 3 Syntax Highlighter
        package com.poolsawat.medium.testrestful;
        import org.springframework.boot.CommandLineRunner;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.context.annotation.Bean;
        import com.poolsawat.medium.testrestful.entity.Blog;
        import com.poolsawat.medium.testrestful.repository.BlogRepository;
        @SpringBootApplication
        public class Application {
        public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        }
        @Bean
        public CommandLineRunner demo(BlogRepository blogRepository) {
        return (args) -> {
        blogRepository.save(new Blog(Long.valueOf("1"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”",
        "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”","poolsawat"));
        blogRepository.save(new Blog(Long.valueOf("2"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”",
        "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”","poolsawat"));
        blogRepository.save(new Blog(Long.valueOf("3"), "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout",
        "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout","poolsawat"));
        };
        }
        }
        package com.poolsawat.medium.testrestful; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import com.poolsawat.medium.testrestful.entity.Blog; import com.poolsawat.medium.testrestful.repository.BlogRepository; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner demo(BlogRepository blogRepository) { return (args) -> { blogRepository.save(new Blog(Long.valueOf("1"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”", "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”","poolsawat")); blogRepository.save(new Blog(Long.valueOf("2"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”", "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”","poolsawat")); blogRepository.save(new Blog(Long.valueOf("3"), "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout", "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout","poolsawat")); }; } }
        package com.poolsawat.medium.testrestful;
        
        import org.springframework.boot.CommandLineRunner;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.context.annotation.Bean;
        
        import com.poolsawat.medium.testrestful.entity.Blog;
        import com.poolsawat.medium.testrestful.repository.BlogRepository;
        
        @SpringBootApplication
        public class Application {
        
          public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
          }
          
          @Bean
          public CommandLineRunner demo(BlogRepository blogRepository) {
            return (args) -> {				
              blogRepository.save(new Blog(Long.valueOf("1"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”", 
                  "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”","poolsawat"));
              blogRepository.save(new Blog(Long.valueOf("2"), "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”", 
                  "SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”","poolsawat"));
              blogRepository.save(new Blog(Long.valueOf("3"), "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout", 
                  "สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout","poolsawat"));
            };
          }
        }
    5. ไฟล์ CrudControllerTest.java
      1. Plain text
        Copy to clipboard
        Open code in new window
        EnlighterJS 3 Syntax Highlighter
        package com.poolsawat.medium.testrestful;
        import static org.hamcrest.CoreMatchers.equalTo;
        import static org.hamcrest.Matchers.hasSize;
        import static org.hamcrest.Matchers.nullValue;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
        import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
        import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
        import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
        import org.springframework.boot.test.context.SpringBootTest;
        import org.springframework.http.MediaType;
        import org.springframework.test.context.junit4.SpringRunner;
        import org.springframework.test.web.servlet.MockMvc;
        @RunWith(SpringRunner.class)
        @SpringBootTest
        @AutoConfigureMockMvc
        public class CrudControllerTest {
        @Autowired
        private MockMvc mockMvc;
        @Test
        public void testShouldSaveBlog() throws Exception {
        String content = "{\"id\" : 4,\"title\" : \"TestRestful\"}";
        this.mockMvc.perform(
        post("/save")
        .content(content)
        .contentType(MediaType.APPLICATION_JSON)
        )
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.title", equalTo("TestRestful")))
        .andExpect(jsonPath("$.content", nullValue()))
        .andExpect(jsonPath("$.author", nullValue()));
        }
        @Test
        public void testShouldGetReturnBlogs() throws Exception {
        this.mockMvc.perform(get("/get"))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$", hasSize(2)));
        }
        @Test
        public void testShouldGetReturnBlogById() throws Exception {
        Integer id = 3;
        this.mockMvc.perform(get("/get/id/"+id))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.id", equalTo(id)))
        .andExpect(jsonPath("$.title", equalTo("สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout")));
        }
        @Test
        public void testShouldDeleteBlogById() throws Exception {
        Integer id = 1;
        this.mockMvc.perform(delete("/id/"+id))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$", equalTo(id)));
        }
        @Test
        public void testShouldUpdateBlog() throws Exception {
        String content = "{\"id\" : 2,\"title\" : \"ShouldUpdateBlog\",\"author\" : \"poolsawat\"}";
        this.mockMvc.perform(
        put("/update")
        .content(content)
        .contentType(MediaType.APPLICATION_JSON)
        )
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.id", equalTo(2)))
        .andExpect(jsonPath("$.title", equalTo("ShouldUpdateBlog")))
        .andExpect(jsonPath("$.content", nullValue()))
        .andExpect(jsonPath("$.author", equalTo("poolsawat")));
        }
        }
        package com.poolsawat.medium.testrestful; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.nullValue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class CrudControllerTest { @Autowired private MockMvc mockMvc; @Test public void testShouldSaveBlog() throws Exception { String content = "{\"id\" : 4,\"title\" : \"TestRestful\"}"; this.mockMvc.perform( post("/save") .content(content) .contentType(MediaType.APPLICATION_JSON) ) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.title", equalTo("TestRestful"))) .andExpect(jsonPath("$.content", nullValue())) .andExpect(jsonPath("$.author", nullValue())); } @Test public void testShouldGetReturnBlogs() throws Exception { this.mockMvc.perform(get("/get")) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(2))); } @Test public void testShouldGetReturnBlogById() throws Exception { Integer id = 3; this.mockMvc.perform(get("/get/id/"+id)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", equalTo(id))) .andExpect(jsonPath("$.title", equalTo("สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout"))); } @Test public void testShouldDeleteBlogById() throws Exception { Integer id = 1; this.mockMvc.perform(delete("/id/"+id)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$", equalTo(id))); } @Test public void testShouldUpdateBlog() throws Exception { String content = "{\"id\" : 2,\"title\" : \"ShouldUpdateBlog\",\"author\" : \"poolsawat\"}"; this.mockMvc.perform( put("/update") .content(content) .contentType(MediaType.APPLICATION_JSON) ) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", equalTo(2))) .andExpect(jsonPath("$.title", equalTo("ShouldUpdateBlog"))) .andExpect(jsonPath("$.content", nullValue())) .andExpect(jsonPath("$.author", equalTo("poolsawat"))); } }
        package com.poolsawat.medium.testrestful;
        
        
        import static org.hamcrest.CoreMatchers.equalTo;
        import static org.hamcrest.Matchers.hasSize;
        import static org.hamcrest.Matchers.nullValue;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
        import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
        import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
        import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
        import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
        
        import org.junit.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
        import org.springframework.boot.test.context.SpringBootTest;
        import org.springframework.http.MediaType;
        import org.springframework.test.context.junit4.SpringRunner;
        import org.springframework.test.web.servlet.MockMvc;
        
        @RunWith(SpringRunner.class)
        @SpringBootTest
        @AutoConfigureMockMvc
        public class CrudControllerTest {
          
          @Autowired
            private MockMvc mockMvc;	
          
          @Test
          public void testShouldSaveBlog() throws Exception {
            String content = "{\"id\" : 4,\"title\" : \"TestRestful\"}";
            this.mockMvc.perform(
                post("/save")
                .content(content)
                .contentType(MediaType.APPLICATION_JSON)
                )
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.title", equalTo("TestRestful")))
                .andExpect(jsonPath("$.content", nullValue()))
                .andExpect(jsonPath("$.author", nullValue()));
          }
          
          @Test
          public void testShouldGetReturnBlogs() throws Exception {
            this.mockMvc.perform(get("/get"))
            .andDo(print())
            .andExpect(status().isOk())        
                .andExpect(jsonPath("$", hasSize(2)));
          }
          
          @Test
          public void testShouldGetReturnBlogById() throws Exception {
            Integer id = 3;
            this.mockMvc.perform(get("/get/id/"+id))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id", equalTo(id)))
                .andExpect(jsonPath("$.title", equalTo("สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout")));
          }
          
          @Test
          public void testShouldDeleteBlogById() throws Exception {
            Integer id = 1;
            this.mockMvc.perform(delete("/id/"+id))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$", equalTo(id)));
          }
          
          @Test
          public void testShouldUpdateBlog() throws Exception {		
            String content = "{\"id\" : 2,\"title\" : \"ShouldUpdateBlog\",\"author\" : \"poolsawat\"}";
            this.mockMvc.perform(
                put("/update")
                .content(content)
                .contentType(MediaType.APPLICATION_JSON)
                )
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id", equalTo(2)))
            .andExpect(jsonPath("$.title", equalTo("ShouldUpdateBlog")))
            .andExpect(jsonPath("$.content", nullValue()))
            .andExpect(jsonPath("$.author", equalTo("poolsawat")));
          }
        }
        
  4. สั่ง mvn spring-boot:run
    1. Plain text
      Copy to clipboard
      Open code in new window
      EnlighterJS 3 Syntax Highlighter
      [INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ MediumTestRestful ---
      [INFO] Nothing to compile - all classes are up to date
      [INFO]
      [INFO] <<< spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) < test-compile @ MediumTestRestful <<<
      [INFO]
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) @ MediumTestRestful ---
      . ____ _ __ _ _
      /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
      \\/ ___)| |_)| | | | | || (_| | ) ) ) )
      ' |____| .__|_| |_|_| |_\__, | / / / /
      =========|_|==============|___/=/_/_/_/
      :: Spring Boot :: (v2.0.5.RELEASE)
      ...
      ...
      2018-12-05 18:51:43.509 INFO 3096 --- [ main] c.p.medium.testrestful.Application : Started Application in 10.0
      65 seconds (JVM running for 16.349)
      [INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ MediumTestRestful --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] <<< spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) < test-compile @ MediumTestRestful <<< [INFO] [INFO] [INFO] --- spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) @ MediumTestRestful --- . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.5.RELEASE) ... ... 2018-12-05 18:51:43.509 INFO 3096 --- [ main] c.p.medium.testrestful.Application : Started Application in 10.0 65 seconds (JVM running for 16.349)
      [INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ MediumTestRestful ---
      [INFO] Nothing to compile - all classes are up to date
      [INFO]
      [INFO] <<< spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) < test-compile @ MediumTestRestful <<<
      [INFO]
      [INFO]
      [INFO] --- spring-boot-maven-plugin:2.0.5.RELEASE:run (default-cli) @ MediumTestRestful ---
      
        .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::        (v2.0.5.RELEASE)
      ...
      ...
      2018-12-05 18:51:43.509  INFO 3096 --- [           main] c.p.medium.testrestful.Application       : Started Application in 10.0
      65 seconds (JVM running for 16.349)
  5. สั่ง mvn test (ไม่ต้อง spring-boot:run แล้ว) เพื่อ run unittest ทดสอบ api CRUD
    1. Plain text
      Copy to clipboard
      Open code in new window
      EnlighterJS 3 Syntax Highlighter
      ...
      [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 12.749 s - in com.poolsawat.medium.testrestful.CrudContr
      ollerTest
      2018-12-05 19:02:23.789 INFO 5576 --- [ Thread-3] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework
      .web.context.support.GenericWebApplicationContext@23e84203: startup date [Wed Dec 05 19:02:12 ICT 2018]; root of context hierar
      chy
      2018-12-05 19:02:23.798 INFO 5576 --- [ Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFa
      ctory for persistence unit 'default'
      2018-12-05 19:02:23.798 INFO 5576 --- [ Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed
      drop of schema as part of SessionFactory shut-down'
      2018-12-05 19:02:23.805 INFO 5576 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown ini
      tiated...
      2018-12-05 19:02:23.811 INFO 5576 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown com
      pleted.
      [INFO]
      [INFO] Results:
      [INFO]
      [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
      [INFO]
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 17.707 s
      [INFO] Finished at: 2018-12-05T19:02:24+07:00
      [INFO] ------------------------------------------------------------------------
      ... [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 12.749 s - in com.poolsawat.medium.testrestful.CrudContr ollerTest 2018-12-05 19:02:23.789 INFO 5576 --- [ Thread-3] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework .web.context.support.GenericWebApplicationContext@23e84203: startup date [Wed Dec 05 19:02:12 ICT 2018]; root of context hierar chy 2018-12-05 19:02:23.798 INFO 5576 --- [ Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFa ctory for persistence unit 'default' 2018-12-05 19:02:23.798 INFO 5576 --- [ Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed drop of schema as part of SessionFactory shut-down' 2018-12-05 19:02:23.805 INFO 5576 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown ini tiated... 2018-12-05 19:02:23.811 INFO 5576 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown com pleted. [INFO] [INFO] Results: [INFO] [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 17.707 s [INFO] Finished at: 2018-12-05T19:02:24+07:00 [INFO] ------------------------------------------------------------------------
      ...
      [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 12.749 s - in com.poolsawat.medium.testrestful.CrudContr
      ollerTest
      2018-12-05 19:02:23.789  INFO 5576 --- [       Thread-3] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework
      .web.context.support.GenericWebApplicationContext@23e84203: startup date [Wed Dec 05 19:02:12 ICT 2018]; root of context hierar
      chy
      2018-12-05 19:02:23.798  INFO 5576 --- [       Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFa
      ctory for persistence unit 'default'
      2018-12-05 19:02:23.798  INFO 5576 --- [       Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed
       drop of schema as part of SessionFactory shut-down'
      2018-12-05 19:02:23.805  INFO 5576 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown ini
      tiated...
      2018-12-05 19:02:23.811  INFO 5576 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown com
      pleted.
      [INFO] 
      [INFO] Results:
      [INFO] 
      [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
      [INFO] 
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  17.707 s
      [INFO] Finished at: 2018-12-05T19:02:24+07:00
      [INFO] ------------------------------------------------------------------------

  6. github source

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *