{"id":33,"date":"2020-09-17T13:47:15","date_gmt":"2020-09-17T12:47:15","guid":{"rendered":"https:\/\/vukieuanh.com\/?p=33"},"modified":"2020-11-26T04:55:13","modified_gmt":"2020-11-26T04:55:13","slug":"test-controller-trong-du-an-spring-boot","status":"publish","type":"post","link":"https:\/\/vukieuanh.net\/index.php\/2020\/09\/17\/test-controller-trong-du-an-spring-boot\/","title":{"rendered":"Test Controller trong d\u1ef1 \u00e1n Spring Boot"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u1ede b\u00e0i tr\u01b0\u1edbc m\u00ecnh \u0111\u00e3 h\u01b0\u1edbng d\u1eabn c\u00e1c b\u1ea1n vi\u1ebft test cho Module Service. So v\u1edbi service, m\u00ecnh kh\u00f4ng c\u1ea7n th\u00eam th\u01b0 vi\u1ec7n khi test Controller. N\u1ebfu d\u1ef1 \u00e1n c\u1ee7a m\u00ecnh c\u00f3 s\u1eed d\u1ee5ng b\u1ea3o m\u1eadt v\u00e0 ph\u00e2n quy\u1ec1n th\u00ec m\u00ecnh th\u00eam th\u01b0 vi\u1ec7n n\u00e0y c\u00e1c b\u1ea1n nh\u00e9. M\u00e0 d\u1ef1 \u00e1n n\u00e0o ch\u1eb3ng c\u00f3 ph\u00e2n quy\u1ec1n nh\u1ec9 -))) <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f3i chung m\u00ecnh th\u00eam th\u01b0 vi\u1ec7n n\u00e0y:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    testImplementation 'org.springframework.security:spring-security-test'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Gi\u1edd m\u00ecnh n\u00f3i qua v\u1ec1 test controller 1 ch\u00fat nh\u00e9. Module Controller nh\u1eadn d\u1eef li\u1ec7u t\u1eeb Module Service. N\u1ebfu m\u00ecnh vi\u1ebft unit test th\u00ec m\u00ecnh ch\u1ec9 c\u1ea7n ki\u1ec3m tra xem service d\u00f9ng \u1edf controller c\u00f3 tr\u1ea3 v\u1ec1 d\u1eef li\u1ec7u \u0111\u00fang hay kh\u00f4ng. Gi\u1ea3 s\u1eed m\u00ecnh mu\u1ed1n test ph\u01b0\u01a1ng th\u1ee9c <code>getAllCategories<\/code> trong Controller.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> @GetMapping(\"\/categories\") \npublic ResponseEntity&lt;Iterable&lt;Categories>> getAllCategories(){\n        return new ResponseEntity&lt;>(categoryService.findAll(), HttpStatus.OK);\n    }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">N\u1ebfu m\u00ecnh vi\u1ebft unit test th\u00ec m\u00ecnh ch\u1ec9 c\u1ea7n l\u00e0m t\u01b0\u01a1ng t\u1ef1 nh\u01b0 test service theo t\u1eebng b\u01b0\u1edbc:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>L\u00e0m gi\u1ea3 CategoryService<\/li><li>N\u00f3i cho Service v\u1eeba \u0111\u01b0\u1ee3c l\u00e0m gi\u1ea3 k\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1 t\u01b0\u01a1ng \u1ee9ng<\/li><li>So s\u00e1nh k\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1 v\u1edbi k\u1ebft qu\u1ea3 mong mu\u1ed1n<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Tuy nhi\u00ean, <code>\u1edf \u0111\u00e2y ch\u00fang t\u00f4i kh\u00f4ng l\u00e0m th\u1ebf<\/code>. Ch\u00fang ta c\u1ea7n t\u1ea1o ra m\u00f4i tr\u01b0\u1eddng MVC gi\u1ea3, t\u1ea1o ra m\u1ed9t c\u1ed5ng gi\u1ea3 \u0111\u1ec3 t\u1ea1o ra m\u1ed9t request face cho vi\u1ec7c test v\u00ed d\u1ee5<code>postface:\/categories<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Spring Boot h\u1ed7 tr\u1ee3 lu\u00f4n cho ch\u00fang ta c\u00e1ch t\u1ea1o ra c\u1ed5ng \u0111\u00f3 c\u00e1c b\u1ea1n nh\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ch\u00fang ta \u0111\u1ec3 \u0111o\u1ea1n m\u00e3 tr\u00ean \u1edf ph\u00eda tr\u00ean ph\u1ea7n kh\u1edfi t\u1ea1o class Test nha c\u00e1c b\u1ea1n.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ti\u1ebfp t\u1ee5c m\u00ecnh c\u1ea7n t\u1ea1o ra m\u1ed9t MVC gi\u1ea3 n\u1eefa c\u00e1c b\u1ea1n \u1ea1. C\u00e1i n\u00e0y d\u00f9ng \u0111\u1ec3 l\u00e0m g\u00ec nh\u1ec9? C\u00e1c b\u1ea1n t\u01b0\u1edfng t\u01b0\u1ee3ng, test Controller m\u00ecnh ph\u1ea3i ki\u1ec3m tra xem m\u00ecnh g\u1eedi request g\u00ec? m\u00ecnh \u0111ang \u1edf role n\u00e0o? m\u00ecnh \u0111\u01b0\u1ee3c tr\u1ea3 v\u1ec1 k\u1ebft qu\u1ea3 th\u1ebf n\u00e0o? ch\u1ee9 \u0111\u00e2u ph\u1ea3i l\u00e0 m\u00ecnh g\u1ecdi ph\u01b0\u01a1ng th\u1ee9c xong m\u00ecnh \u0111i so s\u00e1nh k\u1ebft qu\u1ea3 nh\u01b0 unit test \u1edf service \u0111\u00e2u \u0111\u00fang ko?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MockMvc n\u00f3 s\u1ebd l\u00e0m \u0111i\u1ec1u \u0111\u00f3 cho m\u00ecnh \u0111\u1ec3 \u0111\u1ea3m b\u1ea3o m\u00ecnh kh\u00f4ng c\u1ea7n d\u00f9ng tr\u00ecnh duy\u1ec7t ho\u1eb7c Postman \u0111\u1ec3 l\u00e0m \u0111i\u1ec1u n\u00e0y.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private MockMvc mvc;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Trong class test c\u00e1c b\u1ea1n c\u1ea7n \u0111\u1ebfn service n\u00e0o th\u00ec m\u00ecnh ti\u00eam v\u00e0o nh\u00e9. Trong controller n\u00e0y c\u1ee7a m\u00ecnh m\u00ecnh th\u00eam <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Autowired<br>private ICategoryService categoryService;<br><br>@Autowired<br>private ISkillService skillService;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u1ede \u0111\u00e2y m\u00ecnh c\u00f3 BeforEach nh\u01b0 sau c\u00e1c b\u1ea1n nh\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@BeforeEach\nprivate void init(){\n    \/\/\n    \/\/ M\u00ecnh kh\u1edfi t\u1ea1o c\u00e1c \u0111\u1ed1i t\u01b0\u1ee3ng \u1edf \u0111\u00e2y nh\u00e9.\n    \/\/\n    mvc = MockMvcBuilders\n            .<em>webAppContextSetup<\/em>(applicationContext)\n            .apply(<em>springSecurity<\/em>())\n            .build();\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ph\u1ea7n <code>MockMvcBuilders<\/code> m\u00ecnh th\u00eam ph\u1ea7n <code>applicationContext<\/code> v\u00e0 th\u00eam <em><code>springSecurity<\/code><\/em> c\u1ee7a th\u01b0 vi\u1ec7n sau \u0111\u1ec3 m\u00ecnh d\u1ef1ng \u0111\u01b0\u1ee3c 1 MVC gi\u1ea3 c\u00e1c b\u1ea1n nh\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><br>import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.<em>springSecurity<\/em>;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Gi\u1edd ch\u00fang ta b\u1eaft \u0111\u1ea7u vi\u1ebft Test th\u00f4i n\u00e0o. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">M\u00ecnh test ph\u01b0\u01a1ng th\u1ee9c <code>findAll<\/code> tr\u01b0\u1edbc nh\u00e9. N\u1ed9i dung c\u1ee7a ph\u01b0\u01a1ng th\u1ee9c n\u00e0y nh\u01b0 sau:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@GetMapping(\"\/categories\")<br>public ResponseEntity&lt;Iterable&lt;Categories&gt;&gt; getAllCategories(){<br>    return new ResponseEntity&lt;&gt;(categoryService.findAll(), HttpStatus.<em>OK<\/em>);<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">M\u00ecnh ph\u00e2n quy\u1ec1n cho n\u00f3 l\u00e0 c\u00f3 2 role AMIN v\u00e0 COACH c\u00f3 th\u1ec3 request \u0111\u01b0\u1ee3c \u0111\u01b0\u1eddng d\u1eabn l\u00e0 <code>\/categories<\/code>. V\u00ec v\u1eady \u1edf \u0111\u00e2y m\u00ecnh s\u1ebd test 2 tr\u01b0\u1eddng h\u1ee3p.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">TH1: V\u1edbi role ADMIN s\u1ebd tr\u1ea3 v\u1ec1 HTTPStatus OK.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Test<br>@WithMockUser(username = \"admin\", roles = \"ADMIN\")<br>@DisplayName(\"find all return status 200 with role admin\")<br>void findAll_whenGetCategoriesWithRoleAdmin_thenReturnStatus200() throws Exception {<br>    mvc.perform(<em>get<\/em>(\"\/categories\").contentType(MediaType.<em>APPLICATION_JSON<\/em>))<br>            .andExpect(<em>status<\/em>().isOk());<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">TH2: T\u01b0\u01a1ng t\u1ef1 v\u1edbi role Coach.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Test<br>@WithMockUser(username = \"coach\", roles = \"COACH\")<br>void whengetCategoriesWithRoleCoach_thenReturnStatus200() throws Exception {<br>    mvc.perform(<em>get<\/em>(\"\/categories\").contentType(MediaType.<em>APPLICATION_JSON<\/em>))<br>            .andExpect(<em>status<\/em>().isOk());<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u1ede b\u00e0i tr\u01b0\u1edbc m\u00ecnh \u0111\u00e3 h\u01b0\u1edbng d\u1eabn c\u00e1c b\u1ea1n vi\u1ebft test cho Module Service. So v\u1edbi service, m\u00ecnh kh\u00f4ng c\u1ea7n th\u00eam th\u01b0 vi\u1ec7n khi test Controller. N\u1ebfu d\u1ef1 \u00e1n c\u1ee7a m\u00ecnh c\u00f3 s\u1eed d\u1ee5ng b\u1ea3o m\u1eadt v\u00e0 ph\u00e2n quy\u1ec1n th\u00ec m\u00ecnh th\u00eam th\u01b0 vi\u1ec7n n\u00e0y c\u00e1c b\u1ea1n nh\u00e9. M\u00e0 d\u1ef1 \u00e1n n\u00e0o ch\u1eb3ng c\u00f3 ph\u00e2n [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-33","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/posts\/33","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/comments?post=33"}],"version-history":[{"count":15,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":175,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/posts\/33\/revisions\/175"}],"wp:attachment":[{"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/media?parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/categories?post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vukieuanh.net\/index.php\/wp-json\/wp\/v2\/tags?post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}