อัปเดต, มิถุนายน 2023 : repo และเครื่องมือนี้ไม่ได้รับการดูแลอีกต่อไป โปรดดู go.uber.org/mock สำหรับส้อมที่ดูแลรักษาแทน
Gomock เป็นกรอบการเยาะเย้ยสำหรับภาษาการเขียนโปรแกรม GO มันรวมเข้ากับแพ็คเกจ testing
ในตัวของ GO ได้ดี แต่สามารถใช้ในบริบทอื่น ๆ ได้เช่นกัน
เมื่อคุณติดตั้งไปแล้วให้ติดตั้งเครื่องมือ mockgen
หมายเหตุ : หากคุณยังไม่ได้ทำเช่นนั้นให้แน่ใจว่าได้เพิ่ม $GOPATH/bin
ลงใน PATH
ของคุณ
หากต้องการใช้งานเวอร์ชันล่าสุดที่ปล่อยออกมา:
GO111MODULE=on go get github.com/golang/mock/[email protected]
go install github.com/golang/mock/[email protected]
หากคุณใช้ mockgen
ในไปป์ไลน์ CI ของคุณอาจเหมาะสมกว่าที่จะจับจ้องในรุ่น mockgen ที่เฉพาะเจาะจง คุณควรพยายามทำให้ไลบรารีซิงค์กับรุ่น mockgen ที่ใช้ในการสร้างการเยาะเย้ยของคุณ
mockgen
มีสองโหมดการทำงาน: แหล่งที่มาและไตร่ตรอง
โหมดต้นทางสร้างอินเทอร์เฟซจำลองจากไฟล์ต้นฉบับ มันเปิดใช้งานโดยใช้ธง -source ธงอื่น ๆ ที่อาจเป็นประโยชน์ในโหมดนี้คือ -Imports และ -AUX_FILES
ตัวอย่าง:
mockgen -source=foo.go [other options]
สะท้อนโหมดสร้างอินเทอร์เฟซจำลองโดยการสร้างโปรแกรมที่ใช้การสะท้อนเพื่อทำความเข้าใจอินเทอร์เฟซ มันถูกเปิดใช้งานโดยการผ่านข้อโต้แย้งที่ไม่ใช่แฟลชสองรายการ: เส้นทางนำเข้าและรายการสัญลักษณ์ที่คั่นด้วยเครื่องหมายจุลภาค
คุณสามารถใช้ "." เพื่ออ้างถึงแพ็คเกจเส้นทางปัจจุบัน
ตัวอย่าง:
mockgen database/sql/driver Conn,Driver
# Convenient for `go:generate`.
mockgen . Conn,Driver
คำสั่ง mockgen
ใช้เพื่อสร้างซอร์สโค้ดสำหรับคลาสจำลองที่ได้รับไฟล์แหล่งกำเนิดที่มีอินเทอร์เฟซที่จะล้อเลียน รองรับธงต่อไปนี้:
-source
: ไฟล์ที่มีอินเทอร์เฟซที่จะล้อเลียน
-destination
: ไฟล์ที่จะเขียนซอร์สโค้ดผลลัพธ์ หากคุณไม่ได้ตั้งค่านี้รหัสจะถูกพิมพ์เป็นเอาต์พุตมาตรฐาน
-package
: แพ็คเกจที่จะใช้สำหรับซอร์สโค้ดคลาสจำลองที่เกิดขึ้น หากคุณไม่ได้ตั้งค่าสิ่งนี้ชื่อแพ็คเกจจะถูก mock_
ต่อด้วยแพ็คเกจของไฟล์อินพุต
-imports
: รายการการนำเข้าที่ชัดเจนซึ่งควรใช้ในซอร์สโค้ดผลลัพธ์ที่ระบุไว้เป็นรายการองค์ประกอบที่คั่นด้วยเครื่องหมายจุลภาคของแบบฟอร์ม foo=bar/baz
โดยที่ bar/baz
เป็นแพ็คเกจที่นำเข้าและ foo
เป็นตัวระบุ เพื่อใช้สำหรับแพ็คเกจในซอร์สโค้ดที่สร้างขึ้น
-aux_files
: รายการไฟล์เพิ่มเติมที่ควรได้รับการพิจารณาเพื่อแก้ไขอินเตอร์เฟสแบบฝังตัวที่กำหนดไว้ในไฟล์อื่น สิ่งนี้ถูกระบุว่าเป็นรายการองค์ประกอบที่คั่นด้วยเครื่องหมายจุลภาคของแบบฟอร์ม foo=bar/baz.go
โดยที่ bar/baz.go
เป็นไฟล์ต้นฉบับและ foo
เป็นชื่อแพ็คเกจของไฟล์ที่ใช้โดยไฟล์ -Source
-build_flags
: (สะท้อนโหมดเท่านั้น) ธงผ่านคำต่อคำเพื่อ go build
-mock_names
: รายการชื่อที่กำหนดเองสำหรับการจำลองที่สร้างขึ้น สิ่งนี้ถูกระบุว่าเป็นรายการองค์ประกอบที่คั่นด้วยเครื่องหมายจุลภาคของ Repository=MockSensorRepository,Endpoint=MockSensorEndpoint
, ที่ที่ Repository
เป็นชื่ออินเตอร์เฟสและ MockSensorRepository
เป็นชื่อเยาะเย้ยที่ต้องการ หากหนึ่งในอินเทอร์เฟซไม่มีชื่อที่กำหนดเองการประชุมการตั้งชื่อเริ่มต้นจะถูกใช้
-self_package
: เส้นทางนำเข้าแพ็คเกจเต็มรูปแบบสำหรับรหัสที่สร้างขึ้น จุดประสงค์ของธงนี้คือการป้องกันวงจรการนำเข้าในรหัสที่สร้างขึ้นโดยพยายามรวมแพ็คเกจของตัวเอง สิ่งนี้สามารถเกิดขึ้นได้หากแพ็คเกจของเยาะเย้ยถูกตั้งค่าเป็นหนึ่งในอินพุตของมัน การตั้งค่าสถานะนี้จะบอก Mockgen ว่านำเข้าเพื่อแยกออก
-copyright_file
: ไฟล์ลิขสิทธิ์ที่ใช้เพื่อเพิ่มส่วนหัวลิขสิทธิ์ลงในซอร์สโค้ดผลลัพธ์
-debug_parser
: พิมพ์ผลลัพธ์ตัวแยกวิเคราะห์เท่านั้น
-exec_only
: (โหมดสะท้อน) ถ้าตั้งค่าให้ดำเนินการโปรแกรมสะท้อนนี้
-prog_only
: (โหมดสะท้อน) สร้างโปรแกรมการสะท้อนเท่านั้น เขียนถึง stdout และออก
-write_package_comment
: เขียนความคิดเห็นเอกสารแพ็คเกจ (GODOC) ถ้าเป็นจริง (ค่าเริ่มต้นจริง)
สำหรับตัวอย่างของการใช้ mockgen
ดู sample/
ไดเรกทอรี ในกรณีง่ายๆคุณจะต้องใช้ธง -source
เท่านั้น
type Foo interface {
Bar ( x int ) int
}
func SUT ( f Foo ) {
// ...
}
func TestFoo ( t * testing. T ) {
ctrl := gomock . NewController ( t )
// Assert that Bar() is invoked.
defer ctrl . Finish ()
m := NewMockFoo ( ctrl )
// Asserts that the first and only call to Bar() is passed 99.
// Anything else will fail.
m .
EXPECT ().
Bar ( gomock . Eq ( 99 )).
Return ( 101 )
SUT ( m )
}
หากคุณใช้ GO เวอร์ชัน 1.14+ รุ่นจำลอง 1.5.0+ และกำลังผ่านการทดสอบ *ไปยัง gomock.NewController(t)
คุณไม่จำเป็นต้องโทร ctrl.Finish()
อย่างชัดเจนอีกต่อไป มันจะถูกเรียกให้คุณโดยอัตโนมัติจากฟังก์ชั่นการล้างข้อมูลที่ลงทะเบียนด้วยตนเอง
type Foo interface {
Bar ( x int ) int
}
func SUT ( f Foo ) {
// ...
}
func TestFoo ( t * testing. T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ()
m := NewMockFoo ( ctrl )
// Does not make any assertions. Executes the anonymous functions and returns
// its result when Bar is invoked with 99.
m .
EXPECT ().
Bar ( gomock . Eq ( 99 )).
DoAndReturn ( func ( _ int ) int {
time . Sleep ( 1 * time . Second )
return 101
}).
AnyTimes ()
// Does not make any assertions. Returns 103 when Bar is invoked with 101.
m .
EXPECT ().
Bar ( gomock . Eq ( 101 )).
Return ( 103 ).
AnyTimes ()
SUT ( m )
}
เมื่อผู้จับคู่รายงานความล้มเหลวจะพิมพ์ค่าที่ได้รับ ( Got
) เทียบกับค่าที่คาดหวัง ( Want
)
Got: [3]
Want: is equal to 2
Expected call at user_test.go:33 doesn ' t match the argument at index 1.
Got: [0 1 1 2 3]
Want: is equal to 1
Want
ค่า Want
มาจากเมธอด String()
ของ Matcher หากผลลัพธ์เริ่มต้นของ Matcher ไม่ตรงกับความต้องการของคุณก็สามารถแก้ไขได้ดังนี้:
gomock . WantFormatter (
gomock . StringerFunc ( func () string { return "is equal to fifteen" }),
gomock . Eq ( 15 ),
)
สิ่งนี้จะปรับเปลี่ยนเอาต์พุตของ gomock.Eq(15)
เอาท์พุทสำหรับ Want:
จาก is equal to 15
ถึง is equal to fifteen
Got
ค่า Got
มาจากวิธี String()
ของวัตถุหากมีอยู่ ในบางกรณีผลลัพธ์ของวัตถุนั้นยากที่จะอ่าน (เช่น []byte
) และมันจะเป็นประโยชน์สำหรับการทดสอบเพื่อพิมพ์แตกต่างกัน ต่อไปนี้ปรับเปลี่ยนวิธีการจัดรูปแบบค่า Got
:
gomock . GotFormatterAdapter (
gomock . GotFormatterFunc ( func ( i interface {}) string {
// Leading 0s
return fmt . Sprintf ( "%02d" , i )
}),
gomock . Eq ( 15 ),
)
หากค่าที่ได้รับคือ 3
จะพิมพ์เป็น 03
cannot find package "."
... github.com/golang/mock/mockgen/model
หากคุณเจอข้อผิดพลาดนี้ในขณะที่ใช้โหมดสะท้อนกลับและการพึ่งพาการขายของ
import _ "github.com/golang/mock/mockgen/model"
--build_flags=--mod=mod
ไปยังคำสั่ง mockgen ของคุณ ข้อผิดพลาดนี้เกิดจากการเปลี่ยนแปลงพฤติกรรมเริ่มต้นของคำสั่ง go
ในเวอร์ชันล่าสุด รายละเอียดเพิ่มเติมสามารถพบได้ใน #494