ในระบบงานที่กำลังทำอยู่ มีการเชื่อมต่อกับ AWS resources เช่น S3 เป็นต้น ถ้าเราจะทำชุดการทดสอบอัตโนมัติในส่วนนั้น ประเด็นที่น่าสนใจคือ เราควรจะเชื่อมต่อกับ AWS จริงๆ ไหม คำตอบมันก็ขึ้นอยู่กับความมั่นใจที่เรามีด้วย

ถ้าเราจะต่อกับของจริง เราก็ต้องมาแลกกับ side effect และการจัดการข้อมูลที่ใช้ทดสอบไม่ให้มันปนกับ AWS account จริง แต่ถ้าเรามีเครื่องมือที่สามารถจำลอง AWS ขึ้นมาใน docker container ได้ การจัดการมันก็ง่ายขึ้นนะ งั้นเรามาดูกันว่ามันจะคุ้มไหมนะ ฮ่าๆๆ

ติดตั้ง dependencies

ระบบที่ใช้งานพัฒนาด้วย Spring Boot (อีกแล้ว) ให้ลง dependencies ตามนี้

คำอธิบาย

  • เราเลือกใช้เครื่องมือชื่อ Testcontainers ที่สามารถทำงานร่วมกับ JUnit เพื่อสร้าง container สำหรับการทดสอบ แล้วก็ทำลายทิ้งไปหลังจากใช้งานเสร็จ ดูตัวอย่าง code ใช้งานได้ที่นี่ https://www.testcontainers.org/quickstart/junit_5_quickstart/

  • เราเลือกใช้เครื่องมือชื่อ Localstack จาก Atlassian เพื่อจำลอง AWS บน local machine ซึ่งสามารถ run ผ่าน CLI หรือ Helm ได้ด้วย เราสามารถนำมาประยุกต์ใช้ในการ run local development ได้ด้วย (แต่ประเด็นนี้มันมีข้อจำกัดอยู่ครับ เพราะเนื่องจาก Localstack เขามี feature ตาม tier ด้วย แนะนำให้เรา check ก่อนว่า resource ที่เราต้องการมันอยู่ใน tier ไหนด้วย)

  • Environment ที่เราทดสอบ ไม่ว่าจะเป็น local machine หรือ CI จะต้องมี Docker engine ด้วย ถ้าไม่มีก็แนะนำเราอาจจะต้องจัดการ lifecycle ของ Localstack เอง

Setup Localstack testcontainers

สมมติ implementation ของ AWS S3 ใช้การ STS assume role ที่มี permission ในการไปอ่าน object จาก S3 bucket หน้าตาของ configuration เราจะได้มาประมาณนี้

  • เนื่องจากใน Localstack ก็มี STS feature อยู่ในแบบ open-source ดังนั้นเราสามารถ setup STS assume role เองได้เหมือนกัน หรือเราจะ override AWS S3 configuration นี้ด้วย AWS_ACCESS_KEY_ID และ AWS_SECRET_KEY_ACCESS ซึ่งตรงนี้เดี๋ยว Localstack เค้าจัดการให้ครับ เราไม่ต้องไปสร้างเอง

  • เราจะสร้าง class เพื่อ start และ stop Localstack container ก่อนและหลัง run test suite ตามลำดับ เพื่อให้เราสามารถ reuse ได้กับ test class อื่นๆ แนะนำให้ใช้ JUnit Extension ประโยชน์ที่ได้เลยคือเราจะได้ไม่ต้องมา declare @BeforeAll และ @AfterAll method ทุกๆ test class

เขียนชุดการทดสอบ

ปิดท้ายด้วยการเขียนชุดการทดสอบ อย่าลืมใส่ @ExtendWith(YourCustomAmazonS3Extension.class) ลงไปด้วย

คำอธิบาย

  • อย่างที่บอกไปในหัวข้อที่แล้วคือเราจะ override AWS S3 configuration ดังนั้นเราสามารถสร้าง static inner-class ที่มี @TestConfiguration เพื่อ inject configuration ลงไปใน test ได้ โดยเราจะต้อง configure AWS ให้ไปหา endpoint ของ Localstack ซึ่งปกติจะเป็น http://localhost:4566 แต่ใน testcontainers มันจะสุ่ม ในส่วนของ credentials เราก็ใช้ provider ที่ Localstack มันทำไว้ให้ สาเหตุที่ต้องเอาไปไว้ใน inner-class เพราะเราจะต้องแน่ใจว่า Localstack testcontainer จะต้อง run ก่อน configuration นี้เสมอ และการ override bean ได้เราก็ต้อง enable ใน Spring application config ด้วย แบบนี้
  • เราสามารถ inject configuration ที่เรา override เป็น dependency ได้แล้วก็เรียกใช้ได้เลย แนะนำว่าให้จัดการข้อมูลการทดสอบให้มันไม่มี side effect เช่น delete object และ bucket หลังจากการทดสอบทุก method

หลังจากลองใช้แล้ว พบว่าทีมได้ความมั่นใจเพิ่มขึ้นจากการทดสอบที่ค่อนข้างเร็ว ส่วนที่เราต้องดูต่อไปคือถ้ามี resource อื่นๆ ก็จะต้องมี learning curve ในการประยุกต์ใช้กันไป หรือถ้าเลวร้ายสุดคือ resource มันไม่อยู่ใน open-source tier แล้วจะทำอย่างไร