การตั้งชื่อแพ็กเกจที่เหมาะสมสำหรับการทดสอบด้วยภาษา Go


104

ฉันได้เห็นกลยุทธ์การตั้งชื่อแพ็กเกจการทดสอบที่แตกต่างกันหลายแบบภายใน Go และต้องการทราบว่าข้อดีข้อเสียของแต่ละแบบคืออะไรและควรใช้แบบใด

ยุทธศาสตร์ที่ 1:

ชื่อไฟล์: github.com/user/myfunc.go

package myfunc

ชื่อไฟล์ทดสอบ: github.com/user/myfunc_test.go

package myfunc

ดูตัวอย่างbzip2

ยุทธศาสตร์ที่ 2:

ชื่อไฟล์: github.com/user/myfunc.go

package myfunc

ชื่อไฟล์ทดสอบ: github.com/user/myfunc_test.go

package myfunc_test

import (
    "github.com/user/myfunc"
)

ดูลวดสำหรับตัวอย่าง

ยุทธศาสตร์ที่ 3:

ชื่อไฟล์: github.com/user/myfunc.go

package myfunc

ชื่อไฟล์ทดสอบ: github.com/user/myfunc_test.go

package myfunc_test

import (
    . "myfunc"
)

ดูตัวอย่างสตริง

ไลบรารีมาตรฐาน Go ดูเหมือนจะใช้กลยุทธ์ 1 และ 2 ผสมกันฉันควรใช้ทั้งสามแบบใด มันเป็นความเจ็บปวดที่ผนวกpackage *_testเข้ากับแพ็คเกจการทดสอบของฉันเพราะมันหมายความว่าฉันไม่สามารถทดสอบวิธีการส่วนตัวของแพ็คเกจของฉันได้ แต่อาจมีข้อได้เปรียบที่ซ่อนอยู่ที่ฉันไม่รู้


9
คำถามนี้จะส่งผลให้มีความคิดเห็นที่แตกต่างกันไป แต่ฉันจะโยนให้ฉัน คุณไม่จำเป็นต้องทดสอบวิธีส่วนตัวของคุณ คุณต้องการทดสอบอินเทอร์เฟซของแพ็กเกจของคุณที่นักพัฒนาซอฟต์แวร์รายอื่นจะใช้ หากการทดสอบล้มเหลวคุณจะรู้ว่าวิธีการส่วนตัวของคุณจำเป็นต้องดู
Brenden

2
ตัวอย่าง [wire] ( github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go ) สำหรับกลยุทธ์ที่ 2 ตอนนี้เป็นตัวอย่างของกลยุทธ์ที่ 1 ด้วย ...
durp

คำตอบ:


137

ความแตกต่างพื้นฐานระหว่างสามกลยุทธ์ที่คุณระบุไว้คือรหัสทดสอบอยู่ในแพ็คเกจเดียวกับรหัสที่ทดสอบหรือไม่ การตัดสินใจที่จะใช้package myfuncหรือpackage myfunc_testในไฟล์ทดสอบขึ้นอยู่กับว่าคุณต้องการดำเนินการwhite-boxหรือblack-boxทดสอบ

ไม่มีอะไรผิดปกติกับการใช้ทั้งสองวิธีในโครงการ ตัวอย่างเช่นคุณสามารถมีmyfunc_whitebox_test.goและmyfunx_blackbox_test.goและ

การเปรียบเทียบแพ็คเกจรหัสทดสอบ

  • การทดสอบกล่องดำ:การใช้งานpackage myfunc_testซึ่งจะให้แน่ใจว่าคุณกำลังเพียงแค่ใช้ตัวบ่งชี้การส่งออก
  • การทดสอบกล่องขาว:ใช้package myfuncเพื่อให้คุณสามารถเข้าถึงตัวระบุที่ไม่ได้ส่งออก เหมาะสำหรับการทดสอบหน่วยที่ต้องการเข้าถึงตัวแปรฟังก์ชันและวิธีการที่ไม่ได้ส่งออก

การเปรียบเทียบกลยุทธ์ที่ระบุไว้ในคำถาม

  • กลยุทธ์ที่ 1:ไฟล์myfunc_test.goใช้package myfunc- ในกรณีนี้รหัสทดสอบในmyfunc_test.goจะอยู่ในแพ็คเกจเดียวกับโค้ดที่กำลังทดสอบmyfunc.goซึ่งอยู่myfuncในตัวอย่างนี้
  • กลยุทธ์ที่ 2:ไฟล์myfunc_test.goใช้package myfunc_test- ในกรณีนี้โค้ดทดสอบในmyfunc_test.go"จะถูกคอมไพล์เป็นแพ็กเกจแยกต่างหากจากนั้นเชื่อมโยงและรันด้วยไบนารีทดสอบหลัก" [ที่มา: บรรทัดที่ 58–59 ในซอร์สโค้ดtest.go ]
  • ยุทธศาสตร์ที่ 3:ไฟล์ที่myfunc_test.goใช้package myfunc_testแต่การนำเข้าmyfuncโดยใช้สัญกรณ์จุด - นี้เป็นตัวแปรของยุทธศาสตร์ที่ 2 myfuncแต่ใช้สัญกรณ์จุดที่จะนำเข้า

1
ควรสังเกตว่าการใช้กลยุทธ์ 1 จะเก็บไฟล์ที่_test.goแยกจากแพ็กเกจที่กำลังทดสอบ (ลักษณะการทำงานเดียวกันกับกลยุทธ์ 2) ดูเหมือนจะไม่ได้รับการบันทึกไว้ในgithub.com/golang/go/issues/15315
Kevin Deenanauth

ฉันเห็นแพ็คเกจที่แข็งแกร่งใช้กลยุทธ์ 3 แต่ฉันไม่เข้าใจว่าอะไรคือประเด็น?
PickBoy

1
ฉันแยกแพ็คเกจและทำการเปลี่ยนแปลงและตอนนี้การทดสอบของฉันทั้งหมดพยายามที่จะนำเข้า repo ดั้งเดิมแทนแพ็คเกจที่แยกของฉัน ด้วยกลยุทธ์ที่ 3 ฉันไม่จำเป็นต้องเปลี่ยน "github.com/original/link" เป็น "github.com/my/fork" เพราะเป็นเพียงการอ้างถึง "" แทน.
nmarley

1
@KevinDeenanauth แค่นี้ก็ทำให้ฉันประหลาดใจแล้ว ฉันคิดว่าฉันพบข้อผิดพลาดเมื่อฉันเพิ่งพบชื่อที่_test.goไม่ใช่_testแพ็คเกจซึ่งมีการfunc init()เปลี่ยนแปลงตัวแปรแพ็คเกจส่วนกลางบางอย่างสำหรับการทดสอบ ฉันผิดไป.
Zyl

1
@nmarley .ไม่สามารถแก้ปัญหาส้อมของคุณได้ ไม่ใช่การนำเข้าแบบสัมพัทธ์ เพียงแค่นำเข้าตัวระบุ "ลงในแพ็กเกจปัจจุบัน"
qaisjp

19

ขึ้นอยู่กับขอบเขตของการทดสอบของคุณ การทดสอบระดับสูง (การรวมการยอมรับ ฯลฯ ... ) ควรวางไว้ในแพ็คเกจแยกต่างหากเพื่อให้แน่ใจว่าคุณกำลังใช้แพ็คเกจผ่าน API ที่ส่งออก

หากคุณมีแพ็กเกจขนาดใหญ่ที่มีภายในจำนวนมากที่ต้องผ่านการทดสอบให้ใช้แพ็กเกจเดียวกันสำหรับการทดสอบของคุณ แต่นั่นไม่ใช่คำเชิญสำหรับการทดสอบของคุณเพื่อเข้าถึงรัฐส่วนตัว นั่นจะทำให้การปรับโครงสร้างใหม่กลายเป็นฝันร้าย เมื่อฉันเขียนโครงสร้างไปฉันมักจะใช้อินเทอร์เฟซ เป็นวิธีการเชื่อมต่อที่ฉันเรียกใช้จากการทดสอบของฉันไม่ใช่วิธีการ / ฟังก์ชันตัวช่วยทั้งหมดแยกกัน


13

คุณควรใช้กลยุทธ์ที่ 1 ทุกครั้งที่ทำได้ คุณสามารถใช้foo_testชื่อแพ็กเกจพิเศษเพื่อหลีกเลี่ยงรอบการนำเข้า แต่ส่วนใหญ่จะอยู่ที่นั่นเพื่อให้สามารถทดสอบไลบรารีมาตรฐานด้วยกลไกเดียวกันได้ ยกตัวอย่างเช่นstringsไม่สามารถทดสอบกับกลยุทธ์ที่ 1 ตั้งแต่แพคเกจขึ้นอยู่กับtesting stringsอย่างที่คุณพูดด้วยกลยุทธ์ 2 หรือ 3 คุณไม่มีสิทธิ์เข้าถึงตัวระบุส่วนตัวของแพ็กเกจดังนั้นจึงมักจะดีกว่าที่จะไม่ใช้มันเว้นแต่คุณจะต้องทำ


12
การไม่เข้าถึงตัวระบุส่วนตัวในการทดสอบไม่ใช่คุณธรรมอย่างไร
jub0bs

3
ตามแนวทางการทดสอบที่ดีคุณจะไม่ทดสอบรายละเอียดการใช้งานภายในสำหรับสิ่งประดิษฐ์โค้ด ทำลูกชายเป็นกลิ่นรหัส
Gerardo Lima

0

หมายเหตุสำคัญอย่างหนึ่งที่ฉันต้องการเพิ่มimport .จากGolang CodeReviewComments :

import .รูปแบบจะมีประโยชน์ในการทดสอบว่าเนื่องจากวงกลมอ้างอิงไม่สามารถเป็นส่วนหนึ่งของแพคเกจที่มีการทดสอบ:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

ในกรณีนี้ไฟล์ทดสอบไม่สามารถอยู่ในแพ็กเกจ foo ได้เนื่องจากใช้ bar/testutilซึ่งนำเข้า foo ดังนั้นเราจึงใช้ "นำเข้า" แบบฟอร์มเพื่อให้ไฟล์หลอกว่าเป็นส่วนหนึ่งของแพ็กเกจฟูแม้ว่าจะไม่ใช่

ห้ามใช้import .ในโปรแกรมของคุณยกเว้นกรณีนี้ ทำให้โปรแกรมอ่านยากขึ้นมากเนื่องจากไม่มีความชัดเจนว่าชื่ออย่าง Quux เป็นตัวระบุระดับบนสุดในแพ็กเกจปัจจุบันหรือในแพ็กเกจที่นำเข้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.