วิธีจัดโครงสร้างหน่วยทดสอบสำหรับแอป GUI โดยใช้ C # และ NUnit


16

ฉันถูกขอให้ทำโครงการขนาดเล็กเพื่อจัดหาแอพพลิเคชั่นที่เรียบง่ายให้กับลูกค้าของเรา โดยปกติแล้วฉันจะทำงานกับรหัสแบ็คเอนด์ที่ฉันต้องทำการทดสอบทั้งหมดและฉันยังไม่ได้มีความสุขที่น่าสงสัยในการเขียนการทดสอบสำหรับ GUI ดังนั้นจึงไม่ค่อยชัดเจนสำหรับฉันที่จะตั้งค่า รหัสการทดสอบและเครื่องมือสำหรับ EXE

สัญชาตญาณแรกของฉันคือการรวมการทดสอบด้วยรหัสแอปพลิเคชัน แต่ต้องมีการจัดหาการอ้างอิงเฉพาะสำหรับการทดสอบจำนวนมากซึ่งฉันได้รับคำสั่งให้ไม่ส่งมอบให้กับลูกค้าโดยเฉพาะ ฉันยังไม่สามารถบีบเงินสดเพื่อใช้เป็นเครื่องมือทดสอบที่สร้างขึ้นมาได้ดังนั้นฉันต้องใช้เครื่องมือที่มีอยู่ในมือ ( StoryQ , RhinoMocksและNUnit) ซึ่งควรเกินพอที่จะทดสอบพฤติกรรมของแอพ GUI อย่างง่าย ดังนั้นเท่าที่ฉันเห็นนี่ทำให้ฉันพยายามสร้างสมดุลที่ดีระหว่างการออกแบบให้เรียบง่ายหรือใช้วิศวกรรมมากเกินไปเพื่อการทดสอบ ดูเหมือนว่าฉันกำลังสร้างแอปด้วยตรรกะทางธุรกิจในห้องสมุดแยกต่างหากและทดสอบกับห้องสมุดอย่างที่ฉันมักจะทำหรือค้นหากลไกอื่น ๆ เพื่อให้ฉันสามารถดำเนินการได้โดยไม่แยกโมดูลเพิ่มเติมที่การออกแบบแอปพลิเคชันไม่ ต้องการจริงๆ

แก้ไข:
โปรดทราบว่าคำถามนี้เกี่ยวกับวิธีการจัดโครงสร้างความสัมพันธ์ระหว่าง NUnit และปฏิบัติการของฉัน - ซึ่งต่างกับ DLL - และไม่เกี่ยวกับวิธีแยกงานนำเสนอและตรรกะทางธุรกิจ
/ แก้ไข

ดังนั้นคำถามของฉันคือ:

  1. มีวิธีเฉพาะ / แนะนำสำหรับการกำหนดค่าแอปพลิเคชัน GUI อย่างง่ายพร้อมการทดสอบหน่วยเพื่อให้ฉันตรวจสอบสถานะและพฤติกรรมอย่างเพียงพอโดยใช้เครื่องมือที่ฉันมีอยู่ในมือและไม่ต้องใช้วิธีการทางวิศวกรรมมากเกินไป?
  2. ฉันพลาดพื้นฐานบางอย่างเกี่ยวกับวิธีที่ NUnit ควรเรียกใช้ / กำหนดค่าเมื่อทำการทดสอบ EXE (ตรงข้ามกับ DLL)
  3. คุณสามารถให้หรือชี้ให้ฉันในทิศทางของตัวอย่างของการบรรลุทั้งหมดนี้ได้อย่างไร

ฉันรู้ว่าอาจมีหลายวิธีในการทำเช่นนี้ฉันจึงมองหาแนวทางการใช้งานเฉพาะตามประสบการณ์ของคุณ


NUnit ไม่ได้ออกแบบมาเพื่อทดสอบ GUI โดยตรง คุณต้องแยกเลเยอร์การนำเสนอของคุณ (เช่นมุมมอง) จากข้อมูลและตรรกะทางธุรกิจของคุณ (เช่นรุ่น) เพื่อให้คุณสามารถทดสอบสิ่งที่จะเข้าสู่มุมมองของคุณโดยไม่ต้องใช้มุมมอง
เบอร์นาร์ด

1
@Bernard คำถามนี้ไม่เกี่ยวกับการสร้าง GUI สำหรับการทดสอบ ฉันเลเยอร์แอปทั้งหมดของฉันโดยธรรมชาติ - แม้แต่แอปที่ไม่สำคัญ - ดังนั้นมันจึงไม่ใช่ปัญหาสำหรับฉัน ฉันได้แก้ไขคำถามให้เหมาะกับและฉันหวังว่ามันจะเคลียร์ความเข้าใจผิด ๆ :)
S.Robins

1
ไม่มีอะไรซับซ้อนอย่างมากในการทดสอบหน่วยใน EXE เพียงแค่ให้ DLL ทดสอบอ้างอิงไฟล์ EXE ของคุณและคุณก็พร้อมที่จะไป
whatsisname

คำตอบ:


3

ฉันได้กล่าวถึงหนึ่งในความคิดเห็นของฉันต่อคำตอบของ simoramanว่าฉันคิดถึงวิธีการสองสามอย่าง หนึ่งในตัวเลือกของฉันคล้ายกับคำแนะนำในคำตอบของ Jalayn ในการสร้างโครงการที่ซ้ำกันและสร้าง DLL ในขณะที่ความคิดอื่น ๆ ของฉันคือการเชื่อมโยงไปยังไฟล์ในโครงการที่มีรหัสที่ฉันต้องการทดสอบ ในขณะที่ตัวเลือกทั้งสองสามารถทำงานได้

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

วิธีที่ดีที่สุดดูเหมือนว่าจะทำตามสิ่งที่ชื่อแสดงความคิดเห็นกับคำถามของฉันและเพียงแค่รวม EXE เป็นข้อมูลอ้างอิงในโครงการทดสอบ ปรากฎว่า EXE ได้รับการปฏิบัติอย่างมีประสิทธิภาพเช่นเดียวกับ DLL ในกรณีนี้และฉันสามารถเข้าถึงทุกชั้นของฉันเพื่อทดสอบสิ่งที่ลอยอยู่บนเรือ


2

ฉันคิดว่า:

  • รหัสทดสอบธุรกิจของคุณควรอยู่ในโครงการแยกต่างหากทดสอบไลบรารีรหัสธุรกิจของคุณ
  • รหัสทดสอบ GUI ของคุณควรอยู่ในโครงการแยกต่างหากทดสอบไลบรารี GUI ของคุณ ตอนนี้วิธีการสร้างห้องสมุด GUI แทนการปฏิบัติการฉันพยายามที่จะตอบว่าในภายหลัง
  • หากคุณมี my.namespace.biz.MyClass คลาสทดสอบของคุณควรเป็น my.namespace.biz.MyClassTest (หรือ MyClassTestCase)
  • หากคุณต้องการทดสอบรหัสที่พบในเป้าหมายที่ปฏิบัติการได้ของคุณคุณควรมีการตั้งค่าที่สร้าง EXE และการตั้งค่าอื่นที่สร้าง library (DLL) ซึ่งเป็นสิ่งที่คุณจะทำการทดสอบ

นี่เป็นกฎที่ฉันชอบติดตามไม่ว่าจะเป็น Java หรือ C # (ยกเว้นไม่มีปัญหา EXE กับ Java แน่นอน :-))

สำหรับวิธีกำหนดค่าสภาพแวดล้อมการทดสอบของคุณดูเหมือนว่าคุณมีอย่างน้อยสองตัวเลือกนี้:

ใช้MSBuild

สร้างโคลนของไฟล์. proj ของคุณ (พูดmyproject-as-dll.proj ) เปลี่ยนไฟล์OutputTypeในโคลนจาก " EXE" เป็น " Library" การใช้คำสั่ง MSBuild ตอนนี้คุณสามารถสร้างไลบรารีที่คุณสามารถตั้งเป็นข้อมูลอ้างอิงในโครงการของคุณที่มีกรณีทดสอบ NUnit

ดูเหมือนจะเป็นไปได้สำหรับฉัน แต่ฉันไม่เคยใช้มันอย่างตรงไปตรงมาดังนั้นฉันไม่แน่ใจ นอกจากนี้คุณอาจไม่มี MSBuild บนเซิร์ฟเวอร์ทดสอบรวมของคุณและฉันไม่รู้ว่าสามารถแยกออกจาก Visual Studio ...

ใช้NAnt

หากคุณไม่คุ้นเคยกับ NAnt คุณจะต้อง google ขึ้นวิธีกำหนดค่าโครงการของคุณสร้างด้วย อาจตรวจสอบสิ่งนี้มันค่อนข้างเก่า แต่ผู้เขียนได้ให้ความเห็นไฟล์ NAnt และหากพบว่าตนเองอธิบาย ( แก้ไข: ตรวจสอบไฟล์ของเขาในรายละเอียดมากขึ้น เขายังทำมากกว่าสร้างเพราะเขาดำเนินการกรณีทดสอบและเปิดตัวเครื่องมือครอบคลุมรหัส ตอนนี้ฉันยอมรับว่าฉันไม่เคยใช้ NAnt ตรงกันข้ามกับ Java และพ่อของ "Ant" ที่ฉันใช้บ่อย แต่ฉันเห็นว่ามันค่อนข้างเหมือนกันและฉันไม่คิดว่ามันยากที่จะเรียนรู้

ด้วยเครื่องมือนั้นคุณสามารถกำหนดค่าที่จะช่วยให้คุณ:

  • สร้างโครงการทั้งหมดของคุณ (ตรรกะทางธุรกิจ, GUI, ฯลฯ ) ในไลบรารีแยกต่างหาก
  • สร้างโครงการทดสอบของคุณ
  • เรียกใช้การทดสอบ (ส่วนเฉพาะนั้นทำกับงาน NUnit2 )
  • ตรวจสอบความคุ้มครองรหัสของคุณกับงาน NCover

ด้วยโค้ดอีกเล็กน้อยคุณสามารถทำได้:

  • ดำเนินการปรับใช้ทุกคืนในเซิร์ฟเวอร์การรวมของคุณ
  • ถ้า NAnt มีอยู่ในเซิร์ฟเวอร์การรวมของคุณให้เปิดการทดสอบการรวมระบบทุกค่ำคืนด้วยความช่วยเหลือของงานที่กำหนดเวลาไว้

ทำทั้งหมดโดยไม่เปลี่ยนแปลงอะไรในไฟล์ Visual Studio ของคุณ และจริงๆแล้วมันดูไม่เหมือนวิศวกรรมมากเกินไปสำหรับฉันมันเป็นเพียงไฟล์เดียว อาจใช้เวลาหนึ่งอาจจะใช้เวลาสองวันในการทำให้ทุกอย่างทำงาน แต่คุณจะมีความคิดที่ดีในการตั้งค่า

สุดท้ายนี้ฉันจะมอบสิ่งที่จำเป็นในการสร้างทดสอบและดำเนินโครงการให้กับลูกค้า ฉันมักจะคิดว่ามันแสดงให้เห็นถึงความเป็นมืออาชีพของคุณและความจริงที่ว่าคุณเขียนโค้ดที่มีคุณภาพในใจของคุณ (ซึ่งดูเหมือนว่าฉันจะทำเพราะคุณกำลังมองหาวิธีแก้ปัญหาที่สง่างาม)


0

เพียงเพราะโครงการมีขนาดเล็ก (เริ่มแรก) ไม่ได้หมายความว่าสถาปัตยกรรมที่เหมาะสมเป็นมากกว่าวิศวกรรม ข้อเท็จจริงที่ว่าคุณต้องการเขียนการทดสอบบอกว่าโครงการของคุณไม่ใช่การแฮ็กข้อมูลครั้งเดียวอย่างสมบูรณ์

คุณไม่ได้พูดถึง GUI-Framework ที่คุณใช้ WPF MVVM (Model-View-ViewModel) นั้นดีและให้คุณเขียนแบบทดสอบสำหรับตรรกะทั้งหมดได้อย่างง่ายดาย ด้วย WinForms ฉันได้ยินสิ่งดีๆเกี่ยวกับMVP (Model-View-Presenter)


ฉันเขียนการทดสอบสำหรับรหัสทั้งหมดที่ฉันเขียน แม้แต่สิ่งที่คุณอาจพบว่าน่ารำคาญ ครั้งเดียวที่ฉันไม่ได้ทำการทดสอบคือเมื่อฉันเก็บชั่วคราว ในกรณีนี้ฉันกำลังส่งยูทิลิตี้นอกบ้านให้กับลูกค้าดังนั้นการทดสอบจึงเป็นมากกว่าความหรูหรามันเป็นข้อกำหนดเพื่อตอบสนองมาตรฐานคุณภาพของเรา ในแง่ของ "over engineering" นี่ไม่ใช่ตัวเลือกระหว่างสถาปัตยกรรมที่ดีหรือไม่ดี แต่ควรหลีกเลี่ยงความต้องการในการกำหนดเลเยอร์เพิ่มเติมที่ไม่จำเป็นในตัวอย่างนี้เนื่องจากแอปนี้มีจุดประสงค์เดียวที่มีวงจรชีวิตค่อนข้างสั้น
S.Robins

ในส่วนที่เกี่ยวกับตัวเลือกของกรอบงาน gui นั้นฉันไม่เห็นว่าสิ่งนี้จะส่งผลกระทบต่อวิธีการตั้งค่าสภาพแวดล้อมการทดสอบอย่างไร ฉันกำลังมองหาวิธีเฉพาะในการใช้การทดสอบหน่วยสำหรับเลเยอร์ GUI โดยใช้เครื่องมือที่ฉันมีอยู่ คำตอบนี้ไม่ได้บอกอะไรฉันเกี่ยวกับเรื่องนั้น
S.Robins

Simoraman - ถ้าคุณเอาย่อหน้าแรกที่ตัดสินออกไปสิ่งนี้จะได้รับคำตอบ แก้ไขและฉันจะลบ -1 ของฉัน @ S.Robins โปรดทราบว่าย่อหน้าที่สองมีความเกี่ยวข้องแม้ว่าจะไม่ใช่คำตอบที่ครบถ้วน แต่ก็จะช่วยได้ หากเลเยอร์ GUI ของคุณบางโครงสร้างที่ดีและชัดเจนและตรรกะทางธุรกิจทั้งหมดได้รับการทดสอบโดยการทดสอบหน่วยในระดับ Model อาจเป็นไปได้ว่าคุณไม่จำเป็นต้องผ่านการทดสอบ UI ที่ยุ่งยากเป็นพิเศษ
มาร์กบูธ

1
@ MarkBooth Layering ไม่ใช่ปัญหาจริงๆ ในฐานะที่เป็น simiraman กล่าวถึงฉันสามารถ MVP, MVVM หรือฉันสามารถสร้างบางสิ่งบางอย่างแม้กระทั่งบาง อย่างไรก็ตามฉันมีองค์ประกอบเฉพาะของ GUI ที่จะต้องมีการทดสอบอย่างชัดเจนซึ่งเป็นสาเหตุที่ฉันตัดสินใจเขียนคำถามนี้ขึ้นมา ฉันมีความคิดสองสามอย่างและถ้าแย่ลงก็ยิ่งแย่ลงฉันรู้ว่าในที่สุดฉันจะสามารถแก้ปัญหาและเขียนคำตอบเองได้ อย่างไรก็ตามฉันต้องการเปิดชุมชนนี้ขึ้นเพราะฉันคิดว่ามันจะเป็นคำถามที่ดีสำหรับโปรแกรมเมอร์ ;-)
S.Robins

0

ดูคำตอบของคำถามนี้: ฉันจะตั้งค่า MVP สำหรับโซลูชัน Winforms ได้อย่างไร

ฉันได้เขียนแอปพลิเคชันตัวอย่างที่แสดงให้เห็นว่าฉันเลเยอร์และทดสอบ GUI ของฉันอย่างไร

การอ่านการแก้ไขของคุณ: ใช้เครื่องมือทดสอบที่รวมเข้ากับสภาพแวดล้อมการพัฒนาของคุณ ฉันใช้ ReSharper


ขอบคุณสำหรับคำแนะนำ ReSharper นี่คือเครื่องมือที่ฉันใช้เมื่อพัฒนา น่าเสียดายที่มันไม่ได้ช่วยเมื่อดำเนินการทดสอบบนเซิร์ฟเวอร์รวมการสร้าง นอกจากนี้ยังไม่ได้บอกวิธีกำหนดค่าการทดสอบ Nunit ให้เข้าถึงรหัสใน exe เมื่อทำการทดสอบ
S.Robins

1
มันทำอย่างไม่เป็นทางการ exe เป็นเพียงมุมมองซึ่งโหลดผู้นำเสนอแบบจำลองและมุมมองออกจากไลบรารีคลาสซึ่งเป็นส่วนหนึ่งของการเริ่มต้นแอปพลิเคชัน อย่างน้อยในโซลูชันของฉันมุมมองนั้นโง่พอที่เราจะไม่ทดสอบด้วยการทดสอบอัตโนมัติและเพียงแค่ทำการทดสอบการยอมรับเพื่อให้แน่ใจว่าสะกดถูกและปุ่มอยู่ตรงไหน การทดสอบ NUnit dll นั้นทำได้ง่ายมาก
ไบรอัน Boettcher

0

ฉันเขียน Nunit WinForms ไปหลายปีย้อนหลัง (6 ปีฉันเดา) สิ่งหนึ่งที่ฉันจำได้อย่างเฉพาะเจาะจงคือแม้ว่ามันจะเป็นกรณีทดสอบหน่วย บางครั้งมีการทดสอบที่ส่วนหน้าไม่มากนัก (ฟอร์มง่าย ๆ ) ดังนั้นแม้ว่าคุณจะพยายามทดสอบกล่องข้อความที่โผล่ขึ้นมาเมื่อคลิกปุ่ม แต่คุณกำลังทดสอบวิธีอื่น ๆ จากเลเยอร์อื่นโดยไม่ตั้งใจ มีบางสิ่งที่คุณทำไม่ได้โดยอัตโนมัติเช่นกัน รูปลักษณ์ความรู้สึกและการใช้งานไม่สามารถเป็นแบบอัตโนมัติได้โดยใช้การทดสอบหน่วยอัตโนมัติ คุณจะต้องทำการทดสอบด้วยตนเองก่อนที่จะเผยแพร่


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