Patch ยังไงให้อ่านรู้เรื่อง

Patch ยังไงให้อ่านรู้เรื่อง

สิ่งหนึ่งที่เราจะเจอหลังจากเขียน Unit Test มาได้ซักพักคือ มันจะมีบางอย่างที่เราควบคุมมันไม่ได้ครับ บางอย่างนั้นอาจจะเป็นไปได้ตั้งแต่ ค่าสุ่ม, เวลา, การอ่านเขียนไฟล์,​ การแก้ไข Database อะไรอย่างนี้เป็นต้น

พอเรามาเจออะไรพวกนี้ มันจะเกิดคำถามขึ้นมาทันทีว่า แล้วเราจะเทสมันยังไง ถ้ามันเปลี่ยนตลอดเวลา คำตอบของคำถามนั้นก็คือ เราต้อง Mock มันครับ ซึ่ง Python มี standard library ไว้จัดการเรื่องนี้ครับคือ unittest.mock.patch

Patch นั้นมีหลายท่า ก่อนหน้านี้ผมเคยเล่าให้ฟังบางส่วนแล้วว่าเราจะจัดการกับการ Patch หลายๆ module ยังไง ซึ่งใช้ ExitStack() มาช่วยในการจัดการ context สนใจไปอ่านต่อได้ที่นี่ครับ

Python - ExitStack แบบสั้นๆ
วันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager

แต่จริงๆ เราสามารถใช้ patch ได้ถึง 3 แบบเลย แล้วแต่สถานการณ์ครับ

patch decorator

แบบแรกคือ ใช้เป็น decorator ครับแบบนี้จะเหมาะกับ การที่เรา patch ฟังก์ชั่นจำนวนน้อยๆ ซึ่งพอมันน้อยเนี่ยมันจะยังไม่รบกวน test function signature มาก ทำให้เรา ยังพออ่านได้อยู่ว่า Test Case นั้นชื่ออะไร

patch context

แบบที่สอง น่าจะเคยเห็นมาจาก Tricks ข้างบนแล้วนะครับ คือเราใช้ภายใต้ context manager แทน แบบนี้ทำให้เราไม่ต้องมี decorator มากวนใจตรง function signature แล้วครับ ตัว patch จะถูกใช้ใน test function เลย แต่ข้อเสียคือ เราก็จะเสีย indent ไปนิดหน่อยตอนเราสั่งรัน function ที่เราจะเทส

patch manually

แบบสุดท้าย คือเราจะสั่ง patch เองครับผ่าน method start() และหยุด patch ผ่าน stop() พอเราสั่ง patch แบบนี้แล้ว มันเปิดโอกาสให้เราทำอะไรได้หลายๆ อย่างมากเช่น เรา patch ไว้ตั้งแต่ setUp เลย ถ้าฟังก์ชั่นนี้ต้อง patch ทุก TestCase ซึ่งจะช่วยลด Duplication ของ patch ใน code ไปได้ หรือเราอยากให้ TestCase เรามี indent น้อยๆ ก็จะช่วยได้เหมือนกัน

แต่พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ใหญ่ยิ่งครับ วิธีนี้สำคัญสุดเลยคือ ต้องอย่าลืมหยุด patch ครับ จะสังเกตุว่า ตอนเราใช้ decorator หรือ context manager เราไม่เคยต้องกังวลเรื่องนี้เลย เป็นเพราะว่าพอเราใช้สองอย่างนั้น พอออกจาก context มันจะหยุด path ให้เราอัตโนมัติครับ

ขอสรุปสั้นๆ อีกทีละกันว่าเราควรควรใช้ Patch ท่าไหนตอนไหน

  • patch decorator ใช้เวลาที่เรา patch แค่หนึ่งฟังก์ชั่น
  • patch as context manager ใช้เวลาที่เราจะ patch หลายๆ ฟังก์ชั่น
  • patch manually start / stop ใช้เวลาต้อง patch เหมือนๆ กันทุกฟังก์ชั่นใน Test Suite หรือลดความซ้ำซ้อนของโค้ด

เป็นยังไงกันบ้างครับ การจะ Mock นี่ไม่ใช่เรื่องเล็กๆ เลย ข้อเสียของ patch ของ Python อีกอย่างนึงคือ Official Document อ่านยากมากครับ กว่าจะเข้าใจวิธีใช้ ต้องบอกว่าเทคนิคนี้ผมก็อ่านๆ มาจากหลายๆ Blog เหมือนกันครับ ใครสนใจศึกษาเพิ่มเติมก็ลองดูได้ตามลิ้งข้างล่างเลยครับ

Reference

Python Mock Cookbook
The python mock library is one of the awesome things about working in Python. No matter what code you’re unit testing, it’s possible to mock out various pieces with very little test code. That being said, it’s sometimes difficult to figure out the exact syntax for your situation. I attribute this to…
Test — pysheeet
The many flavors of mock.patch
I write a lot of unit tests. Unfortunately, my code often requires monkey patching to be properly unit tested. I frequently use the patch function …

Original post at: https://medium.com/pythonbycow/patch-ยังไงให้อ่านรู้เรื่อง-8d504b01b1ec