Restful Spring-Boot + Unit Test Part 1

Pawut Jingjit
4 min readMay 19, 2022

Spring Initializr , Entity , Repository and Unit Test

Requirements

ทั้ง JDK , Build tools ( Gradle , Maven ) ต้องการ Set Path ด้วย

สำหรับเพื่อนๆที่ต้องการความสบายในการติดตั้ง เจ้าของบทความแนะนำให้ใช้ IDE เป็น VSCode แล้วติดตั้ง Extension Pack for Java , Spring Boot Tools

หลังติดตั้ง Extension แล้ว สามารถกด Ctrl + Shift + P -> Java: Install New JDK เพื่อติดตั้ง JDK ได้ใน VSCode เลย

ติดตั้งผ่านVSCode ไม่ต้อง Set Path ด้วยนะ แถม Build Tools สามารถ ใช้รุ่น Wrapper ใน Project ได้เลย สรุป ติดตั้งแค่ IDE อย่างเดียว ก็เริ่มต้น Dev ได้เลย

Task

ทาง Manager ต้องการสร้าง Landing Page ที่จะแสดงสินค้าของทางบริษัท แต่สินค้าของบริษัทมีการเปลี่ยนแปลงบ่อย ไม่สะดวกที่จะใช้แบบ Static จึงมอบหมายให้ทีม Backend สร้าง API ตามนี้

  • GET : แสดง Product ทั้งหมด
  • CREATE : สร้าง Product ใหม่
  • EDIT : แก้ไข Product By ID
  • DELEET : ลบ Product BY ID
  • GET : ค้นหา Product BY ID
  • GET : ค้นหา Product ด้วย Product name

โดยแต่ละ Product จะมี

  • Product name : ชื่อของ Product
  • Price : ราคาของ Product
  • Describe : รายละเอียดของ Product

Spring Initializr

ถ้าเพื่อนๆคุ้นเคยกับ Framework จะทราบดีว่า การจะเริ่มสร้าง Project ซัก Project หนึ่ง เป็นเรื่องที่เสียเวลาอย่างมาก Framework ส่วนใหญ่จึงมีตัว Initializr ให้ (อย่าง React ก็เป็น create-react-app )

เริ่มจากเข้าไปที่ Spring Initializr

ใช้เป็น Defualt ได้เลย ที่สำคัญคือส่วนของ Dependencies

Dependencies

เพื่อให้ Spring Boot สามารถทำ Task ตามที่ต้องการได้ จึงต้องติดตั้ง Dependencies เพิ่มเติม

สำหรับ Project แรก สามารถติดตั้งตามเจ้าของบทความได้เลย

สำหรับ Project นี้ สามารถติดตั้งตามนี้ได้(สามารถเพิ่มเติมทีหลังได้ ถ้าขาดอะไรไป)
  • Spring Web : จะทำ Restful API จะขาดตัวนี้ไม่ได้เลย
  • H2 : เป็น Database Default ของ Spring ไม่ต้อง Config อะไรเพิ่มเติม
  • JPA : เป็น Quary พื้นฐานให้เรียกใช้ จะอธิบายละเอียดในบทความ
  • DevTools : เจ้าของบทความใช้ในฐานะ Live Reload เท่านั้น
  • Lombok : ใครเคยไม่ชอบ Java เพราะต้องมานั่งเขียน getter setter ต้องถูกใจ บอกลาการเขียน Object ที่มี Attibute 10 ตัว แต่มี getter setter รวมกันเกิน 50 Line

จากนั้นสามารถ Generate แล้วนำมาเปิดด้วย IDE ได้เลย ซึ่งเปิดครั้งแรกจะนานหน่อย เพราะ IDE จะพยายาม Download มาทั้งตัว Wrapper และ Dependencies

หลังจาก Open Project ไปที่ DemoApplication แล้วกดลูกศรเขียวดังภาพ

กดที่ลูกศรเขียว // ในบทความนี้จะใช้ IDE เป็น InteliJ แทน เพราะ VSCode ของเจ้าของบทความลงบ้าลงบอจนทำงานช้าแล้ว Zzz
ถ้าทำทุกขั้นตอนถูกต้อง หลังจากรันแล้ว เราจะสามารถเข้าถึง localhost:8080 ได้

Boilerplate code

มาพักครึ่งทางกับคำศัพท์ที่เพื่อนๆน่าจะเจอบ่อยๆซักหน่อย เพื่อนๆอาจสงสัยว่า Lombok มีไว้เพื่อลด “Boilerplate Code”

คำว่า “Boilerplate Code” หมายถึงอะไรกันนะ

boilerplate code, or simply boilerplate, are sections of code that are repeated in multiple places with little to no variation

Boilder Plate หมายถึงโค๊ตที่ถูกเขียนซ้ำๆในหลายๆที่โดยที่ทำงานใกล้เคียงกัน

สังเกตว่า โค๊ต getter setter เต็มไปหมด ทำหน้าที่เดียวกันเป้ะ แค่ต่างตัวแปรกัน
เราสามารถใช้ Lombok Annotation เพื่อลด Bolier Plate ให้เหลือเพียง Setter Getter Annotation ได้

Entity

An entity is a lightweight persistence domain object. Typically, an entity represents a table in a relational database.

  • ว่าง่ายๆ Entity คือ Object ที่เป็นตัวแทนของ Table ใน Database
  • ถ้าใน Database มี Table ใด ถ้าเราจะติดต่อกับ Database นั้น ต้องมี Entity เดียวกับ Database นั้น
เริ่มจากสร้าง Folder entity และ ProductEntity ดังภาพ
ถ้าพิมพ์เอง IDE จะ Recommend ว่าจะ Import Annotation ไหม ( คือถ้า Ctrl C+V มันจะไม่ import มาให้ ) ที่สำคัญคือ Annotation ID (Line 6) มี 2 ตัว ให้ใช้ javax.persistence.Id นะ
  • Entity Annotation : Class นี้คือ Entity
  • ID Annotaion : Field นี้คือ ID ซึ่งเป็น ID เดียวกับ Database

Repository

The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.

เพื่อนๆที่คุ้นเคยกับ Backend คงรู้จักกับ CRUD( Create , Read , Update , Date ) อยู่แล้วใช่ไหม? เพื่อนๆเคยคิดรึเปล่าว่า ไม่ว่าจะ Project ใดๆ แทบจะมีคุณสมบัติพื้นฐานของ CRUD เสมอ

เพื่อลด Boilerplate Code ทาง Spring boot จึงพัฒนา Repository ขึ้น

สร้าง repository Folder และ Product Repository ดังภาพ
เช่นเดิม ต้องพิมพ์เอง ห้าม Ctrl+C,V
  • Repository Annotation : Class นี้คือ Repository
  • Long ใน JpaRepository คือ Type ของ ID Annotation ใน Entity

เพียงแค่ Extends JpaRepository เราก็ได้ Create , Find All มาแล้ว

Unit Test

Unit testing ensures that all code meets quality standards before it’s deployed

สารภาพมานะ Code ใครยังทำงานแบบนี้อยู่มั้ง

เพื่อนๆมั่นใจได้ 100% ว่าแต่ละ Line ที่เพื่อนๆโค๊ตลงไป ทำงานตามที่เพื่อนๆคิดไว้ ใน Project ที่ใหญ่ขึ้นไป อาจจะเป็นไปไม่ได้ที่เราจะทดสอบทุกกรณีที่เป็นไปได้ในโปรแกรม

แล้วถ้าวันหนึ่ง เราต้องการ Update Feature ของเราขึ้นมา เราจะมั่นใจได้อย่างไรว่า Code ที่เคยถูกต้องนั้น ยังจะทำงานถูกต้องอยู่

เพราะแบบนี้ เราจึงต้องการ Automated Testing และ Autometed Testing ที่สามารถทำได้ง่ายที่สุดคือ

Unit Test

อนึ่ง Spring ได้เตรียม Unit Test ดีๆอย่าง Junit มาให้ใช้ โดยไม่ต้องติดตั้ง dependency เพิ่มเติม

Repository Unit Test

จัด test Folder ล้อมาจาก main ได้เลย
ในเมื่อต้องการ test JPA ก็ต้องใช้ Annotation DataJpaTest // อย่างไรก็ดี ปกติจะไม่มีใครเขียน unit test ของ save , findAll กัน เพราะ extends มาจาก jpa มันไม่ควรจะทำงานผิดได้ เสร็จแล้วกดปุ่ม

การเขียน Unit Test จะแบ่งเป็น 3 ส่วนเสมอ ในที่นี้จะสร้าง Unit Test สำหรับ findAll

  • given : ก่อน Test จะ Assign อะไรบ้าง
  • when : ต้องการทดสอบอะไร( ในที่นี้คือ findAll Function ) ผลลัพท์เก็บไว้ใน Result
  • then ตรวจสอบ Result ว่าเป็นไปตามที่คาดการณ์ไหม

ในเมื่อ save product 3 unit เมื่อ findAll จึงควรจะได้รับ Result เป็น List<Product> Size เท่ากับ 3 ซึ่งเป็นไปตามที่คาดการณ์ไว้

กด Test ที่ปุ่มเขียว ควรจะได้ผลลัพท์ตามภาพ

สังเกตว่า เราสามารถใช้ save , findAll ของ ProductRepository ได้ โดยที่ไม่จำเป็นต้อง Implement เองเลย

ที่ต้องรู้คือ สำหรับ DataJpaTest Annotation จะไม่ไป Save ใน database จริงๆ แต่จะ rollback หลังจากที่ Test เสร็จแล้ว

สำหรับเพื่อนๆที่อาจจะตามไม่ทัน หรือเขียนตามแล้วเกิดปัญหา สามารถไปดู Code ที่เจ้าของบทความเขียนได้ที่ Github

ส่งท้าย

ก่อนหน้านี้ เจ้าของบทความเป็นติ่ง JavaScript ทั้ง React & NodeJS แต่ได้รับโอกาศในการเข้าค่าย Java Software Engineering Bootcamp ที่ทาง KBTG เป็น Sponser

ต้องบอกว่า เจ้าของบทความไม่ชอบในตัว JavaScript หลายๆอย่าง

  • ตัวแปรที่ไม่มี Type เสี่ยงต่อการเขียนให้ Bug มาก แล้วแก้ไขได้ยาก
  • Framework อย่าง ExpressJs ต้องการ Library เสริมอีกไม่รู้กี่ตัว มีหลายๆตัวหน้าที่เหมือนกัน แต่คนละ Library ก็เยอะ ทำให้ตัดสินใจได้ยากว่าจะใช้อันไหน
  • Testing สามารถทำได้ยาก // หลายคนเขียน JS แบบไม่ Test เลยก็เยอะ

แต่เมื่อมาเรียน Spring จะไม่เจอปัญหาเหล่านี้เลย ตัว Spring เองแทบจะจัดเตรียมทุกอย่างให้เราใน Framework อยู่แล้ว แถมการเขียน Unit Test เป็น default ของการ Develop คือแค่ init ก็มี test folder มายัดมือแล้ว

สุดท้ายก็ขอขอบคุณผู้อ่านทุกๆท่าน ที่อ่านมาถึงตรงนี้ หรือจะ Skip มาตรงนี้เลยก็ตาม ถ้ามีตรงไหนไม่เข้าใจ มีข้อติชมอะไร สามารถมาที่ Page AstralAria นะครับ

ในตอนจบบทความ เราจะสามารถ create , findAll ใน database ได้แล้ว ในบทความหน้า เราจะมาเติม edit , delete , findBy รวมไปถึงพัฒนา restful ของเรา ให้สามารถใช้งานได้จริงๆ ผ่าน API กันครับ

พบกันใหม่ในบทความ Restful Spring-Boot + Unit Test Part 2 ครับ

Reference

Spring Initz

Spring.io

ascend medium

--

--