Mock Object ในภาษา Python

Mock Object คืออะไร
Mock Object คือวิธีการที่ใช้ในการกำหนดพฤติกรรม Object เพื่อให้ได้ผลลัพธ์ที่ใช้ในการทำ Unit Test ตาม Environment ที่ต้องการ โดยจะเป็นการสมมุติว่า ฟังก์ชันทำงานถูกต้องและจะทำการ Mock ข้อมูลขึ้นมาเพื่อใช้ทำการทดสอบ
สาเหตุที่ต้องใช้หลัก ๆ Python Mock Object เพื่อควบคุมสิ่งที่เกิดขึ้นในการทำ UnitTest
ในบางครั้ง ต้องทำการทดสอบฟังก์ชัน เช่น get_coin_price ซึ่งจะทำการแสดงข้อมูลราคาของเหรียญ โดยดึงจากฐานข้อมูล ซื่งถ้าใช้ฐานข้อมูลจริงในบางครั้งผลลัพธ์ที่ได้อาจจะไม่ถูกต้อง เพราะฐานข้อมูลอาจจะมีการเปลี่ยนแปลงซึ่งยากที่จะควบคุม ดังนั้น จึงเป็นสาเหตุที่ดีกว่าที่จะทำการทดสอบโค้ดในสถานการที่ควบคุมได้ โดยการใช้ Mock Object เพื่อทำการจะให้ฟังก์ชันได้ผลลัพธ์จะเป็นทั้ง successful or failures response
ภาษา Python นั้นได้มี Library สำหรับการทำ unittest mock โดยสามารถทำการติดตั้งผ่าน Pip package manager ได้เลย
$ pip install mock
การประกาศ Mock Object
from unittest.mock import Mock
mock = Mock()
print(mock)>> <Mock id='140519256300896'>
การประกาศ Mock Object สำหรับ Mock Function
from unittest.mock import Mock
mock = Mock()
print(mock.get_coin_price()) >> <Mock name='mock.get_coin_price()' id='140379447928048'>
assert_called_once เป็นการตรวจสอบว่า mock object นั้นได้ถูกเรียก 1 ครั้ง
โดยจากโค้ดทำการ Mock Object ให้ทำการเรียกใช้ a_plus_b() โดยจะทำการตรวจสอบว่าฟังก์ชันนี้ได้ทำการเรียกใช้แล้ว 1 ครั้งหรือไม่
from unittest.mock import Mock
def a_plus_b(a,b): return a+b
mock = Mock()
mock.a_plus_b()
mock.a_plus_b.assert_called_once()
หากทำการลบ mock.a_plus_b() ก็จะทำให้มันไม่ถูกเรียกใช้ และการทดสอบจะ fail
assert_called_with เป็นการตรวจสอบว่า Mock Object นั้นได้ถูกเรียกด้วยข้อมูลชุดนี้หรือไม่
โดยจากโค้ดทำการ Mock Object ขี้นมา mock.a_plus_b(a=20, b=25) โดยให้รับตัวแปร 2 ตัว จากนั้นบรรทัดถัดไปจึงมาทำการตรวจสอบว่าฟังก์ขั่นถูกเรียกด้วยข้อมูลที่เหมือนกันหรือไม่
from unittest.mock import Mock
def a_plus_b(a,b): return a+b
mock = Mock()
mock.a_plus_b(a=20, b=25)
mock.a_plus_b.assert_called_with(a=20, b=25)
return_value ใช้ในการตั้งค่าข้อมูลที่จะถูกส่งกลับมาจาก Mock Object ของฟังก์ชัน โดยจากโค้ดจะทำการตั้งค่าให้ข้อมูลที่ถูกส่งกลับมาคือ 30
from unittest.mock import Mock
def a_plus_b(a,b): return a+b
value = 30
mock = Mock()# ทำการ set ค่าให้ส่ง 30 กลับมาเมื่อเรียกใช้
mock_value = mock.a_plus_b().return_value = value
assert mock_value == value
print(mock.a_plus_b().return_value)>> 30
side_effect เป็นการ Mock Object ให้ฟังก์ชันที่โดน Mock นั้นเกิดผลลัพธ์ได้หลายแบบ เช่นจากโด้ดจะตั้งค่าให้หากเรียกใช้ครั้งแรกให้ใช้ค่าเลข 3 หากถูกเรียกครั้งถัดมาจะเป็น 2 ตามลำดับ และในฟังก์ชันสามารถรับค่าเป็น list หรือ ฟังก์ชันได้
from unittest.mock import Mock
mock = Mock()
mock.side_effect = [3, 2, 1]
print(mock(), mock(), mock())>> 3 2 1
call_count เป็นฟังก์ชันที่ใช้ในการนับจำนวนครั้งที่ฟังก์ชันที่ทำการ Mock Object ถูกเรียกใช้งาน
mock = Mock(return_value=None)
print(mock.call_count)>> 0
mock()
mock()
mock.call_count
print(mock.call_count)>> 2
ตัวอย่างการใช้ mock object ใน unittest
ถัดไปจะเป็นตัวอย่างการ Mock Object ทั้ง Request และ Response เนื่องจากต้องการทดสอบว่าหากทำการเรียกใช้ API ไป 2 ครั้ง โดยครั้งแรกจะควบคุมให้เมื่อเรียกใช้ API ให้บังคับให้เกิดเหตุการณ์ request timeout ส่วนครั้งที่ 2 สามารถเรียกใช้ ได้ปกติและได้ข้อมูลกลับมา
import unittest
from unittest.mock import Mock
from requests.exceptions import Timeout# Mock request
requests = Mock()
def get_bitcoin_price(): r = requests.get('http://localhost/api/crypto') if r.status_code == 200: return r.json() return None
class TestCrypto(unittest.TestCase): def test_crypto(self): # Mock response response_mock = Mock() response_mock.status_code = 200 response_mock.json.return_value = { 'name': 'Bit Coin', 'price': 40000, 'rank': 1, } # Set side_effect สำหรับ .get method requests.get.side_effect = [Timeout, response_mock] # ทดสอบให้การเรียกใช้ครั้งแรกติด Timeout with self.assertRaises(Timeout): get_bitcoin_price() # ทดสอบครั้งที่สองสำเร็จให้ตรวจสอบข้อมูล price มีค่าเท่ากีบ 40000 assert get_bitcoin_price()['price'] == 40000 # ทำการทดสอบ .get method ถูกเรียกใช้ไป 2 ครั้ง assert requests.get.call_count == 2
if __name__ == '__main__': unittest.main()
แหล่งอ้างอิง
• Unittest.mock — Mock object library, Python Development Tool.
• Understanding the Python Mock Object Library, by Alex Ronquillo.


Subscribe to follow product news, latest in technology, solutions, and updates
Other articles for you



Let’s build digital products that are simply awesome !
We will get back to you within 24 hours!Go to contact us








