คำถามของคุณเกี่ยวกับว่าเฟรมเวิร์ก MS Fakes แตกต่างจาก NMock อย่างไรและดูเหมือนว่าคำตอบอื่น ๆ ได้แก้ไขบางส่วนแล้ว แต่นี่คือข้อมูลเพิ่มเติมเกี่ยวกับวิธีการที่เหมือนกันและแตกต่างกันอย่างไร NMock ก็คล้ายกับ RhinoMocks และ Moq ดังนั้นฉันจึงจัดกลุ่มพวกมันด้วย NMock
มีความแตกต่างที่สำคัญ 3 ประการที่ฉันเห็นระหว่าง NMock / RhinoMocks / Moq และ MS Fakes Framework:
เฟรมเวิร์กปลอมของ MS ใช้โค้ดที่สร้างขึ้นเช่นเดียวกับ Accessors ใน Visual Studio เวอร์ชันก่อนหน้าแทนที่จะเป็นประเภททั่วไป เมื่อคุณต้องการใช้เฟรมเวิร์กปลอมสำหรับการอ้างอิงคุณเพิ่มแอสเซมบลีที่มีการอ้างอิงกับการอ้างอิงของโปรเจ็กต์ทดสอบจากนั้นคลิกขวาที่มันเพื่อสร้างการทดสอบเป็นสองเท่า (สตับหรือชิม) จากนั้นเมื่อคุณทำการทดสอบคุณจะใช้คลาสที่สร้างขึ้นเหล่านี้แทน NMock ใช้ generics เพื่อบรรลุสิ่งเดียวกัน (เช่นIStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()
) ในความคิดของฉันแนวทางกรอบ MS Fakes ยับยั้งการนำทางโค้ดและการปรับโครงสร้างใหม่จากภายในการทดสอบเนื่องจากคุณกำลังทำงานกับคลาสที่สร้างขึ้นไม่ใช่อินเทอร์เฟซจริง
นางสาวปลอมสมบูรณ์วัสดุกรอบและไฝ (shims) ในขณะที่ NMock, RhinoMocks และ Moq ทั้งหมดให้สมบูรณ์และmocks ฉันไม่เข้าใจการตัดสินใจของ MS ที่จะไม่รวมการล้อเลียนและฉันเองก็ไม่ได้เป็นแฟนตัวยงด้วยเหตุผลที่อธิบายไว้ด้านล่าง
ด้วยกรอบงานปลอมของ MS คุณสามารถจัดหาวิธีการอื่นที่คุณต้องการใช้ในการตัดทอน ภายในการใช้งานทางเลือกเหล่านี้คุณสามารถระบุค่าที่ส่งคืนและติดตามข้อมูลเกี่ยวกับวิธีการหรือวิธีการเรียกใช้เมธอด ด้วย NMock, RhinoMocks และ Moq คุณจะสร้างวัตถุจำลองจากนั้นใช้วัตถุนั้นเพื่อระบุค่าการส่งคืนที่ถูกตรึงหรือเพื่อติดตามการโต้ตอบ (วิธีการเรียกใช้และวิธีการ) ฉันพบว่าวิธีการปลอมของ MS ซับซ้อนกว่าและแสดงออกน้อยกว่า
เพื่อชี้แจงความแตกต่างในสิ่งที่กรอบการทำงานมีให้: NMock, RhinoMocks และ Moq ล้วนมีการทดสอบสองประเภท (ต้นขั้วและม็อก) เฟรมเวิร์กของปลอมมีต้นขั้วและโมล (พวกเขาเรียกมันว่า shims) และน่าเสียดายที่ไม่มีการล้อเลียน เพื่อให้เข้าใจถึงความแตกต่างและความคล้ายคลึงกันระหว่าง NMock และ MS Fakes การทำความเข้าใจประเภทการทดสอบที่แตกต่างกันเหล่านี้คืออะไร:
Stubs: Stubs ใช้เมื่อคุณต้องการระบุค่าสำหรับวิธีการหรือคุณสมบัติที่จะถูกถามถึงการทดสอบของคุณเป็นสองเท่าโดยวิธีการภายใต้การทดสอบ ตัวอย่างเช่นเมื่อวิธีการของฉันภายใต้การทดสอบเรียกใช้เมธอด DoesStudentExist () ของการทดสอบ IStudentRepository สองครั้งฉันต้องการให้มันคืนค่าจริง
ความคิดของต้นขั้วใน NMock และ MS ปลอมเหมือนกัน แต่ด้วย NMock คุณจะทำสิ่งนี้:
Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));
และด้วย MSFakes คุณจะทำสิ่งนี้:
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
DoesStudentExistInt32 = (studentId) => { return new Student(); }
};
ข้อสังเกตในตัวอย่าง MS Fakes คุณสร้างการใช้งานใหม่ทั้งหมดสำหรับเมธอด DoesStudentExist (โปรดสังเกตว่ามันถูกเรียกว่า DoesStudentExistInt32 เนื่องจากกรอบงานปลอมจะผนวกชนิดข้อมูลพารามิเตอร์เข้ากับชื่อเมธอดเมื่อสร้างวัตถุต้นขั้วฉันคิดว่าสิ่งนี้บดบังความชัดเจนของ การทดสอบ) ความจริงแล้วการใช้งาน NMock ยังทำให้ฉันมีข้อบกพร่องเพราะใช้สตริงเพื่อระบุชื่อวิธีการ (ยกโทษให้ฉันถ้าฉันเข้าใจผิดว่าตั้งใจจะใช้ NMock อย่างไร) วิธีนี้ยับยั้งการปรับโครงสร้างใหม่ได้จริง ๆ และฉันขอแนะนำ RhinoMocks หรือ Moq มากกว่า NMock ด้วยเหตุผลนี้
Mocks: Mocks ใช้เพื่อตรวจสอบการโต้ตอบระหว่างวิธีการของคุณภายใต้การทดสอบและการอ้างอิง ด้วย NMock คุณทำได้โดยตั้งความคาดหวังไว้ในลักษณะนี้:
Expect.Once.On(mockStudentRepository).Method("Find").With(123);
นี่เป็นอีกเหตุผลหนึ่งที่ฉันชอบ RhinoMocks และ Moq มากกว่า NMock NMock ใช้รูปแบบการคาดหวังที่เก่ากว่าในขณะที่ RhinoMocks และ Moq ทั้งคู่สนับสนุนวิธีการจัดเรียง / กระทำ / ยืนยันซึ่งคุณระบุการโต้ตอบที่คาดว่าจะเป็นการยืนยันเมื่อสิ้นสุดการทดสอบเช่นนี้ :
stubStudentRepository.AssertWasCalled( x => x.Find(123));
โปรดทราบอีกครั้งว่า RhinoMocks ใช้แลมด้าแทนสตริงเพื่อระบุวิธีการ เฟรมเวิร์กปลอมของ ms ไม่ได้มีการล้อเลียนเลย ซึ่งหมายความว่าในการใช้งานที่ไม่มีการตัดทอน (ดูคำอธิบายของต้นขั้วด้านบน) คุณต้องตั้งค่าตัวแปรที่คุณตรวจสอบในภายหลังว่าตั้งค่าถูกต้อง จะมีลักษณะดังนี้:
bool wasFindCalled = false;
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository()
{
DoesStudentExistInt32 = (studentId) =>
{
wasFindCalled = true;
return new Student();
}
};
classUnderTest.MethodUnderTest();
Assert.IsTrue(wasFindCalled);
ฉันพบว่าวิธีนี้มีความซับซ้อนเล็กน้อยเนื่องจากคุณต้องติดตามการโทรในต้นขั้วแล้วยืนยันในภายหลังในการทดสอบ ฉันพบว่า NMock และโดยเฉพาะ RhinoMocks เป็นตัวอย่างที่แสดงออกได้ชัดเจนมากขึ้น
ไฝ (ชิม):พูดตรงๆฉันไม่ชอบโมลเพราะมีโอกาสใช้ผิดประเภท สิ่งหนึ่งที่ฉันชอบมากเกี่ยวกับการทดสอบหน่วย (และโดยเฉพาะอย่างยิ่ง TDD) คือการทดสอบโค้ดของคุณช่วยให้คุณเข้าใจว่าคุณเขียนโค้ดที่ไม่ดีตรงไหน เนื่องจากการทดสอบโค้ดที่เขียนไม่ดีนั้นทำได้ยาก สิ่งนี้ไม่เป็นความจริงเมื่อใช้โมลเนื่องจากไฝได้รับการออกแบบมาเพื่อให้คุณทดสอบกับการพึ่งพาที่ไม่ได้ฉีดหรือเพื่อทดสอบวิธีการส่วนตัว มันทำงานคล้ายกับต้นขั้วยกเว้นว่าคุณใช้ ShimsContext ดังนี้:
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}
ความกังวลของฉันกับ shims คือผู้คนจะเริ่มมองว่าพวกเขาเป็น "วิธีที่ง่ายกว่าในการทดสอบหน่วย" เพราะไม่ได้บังคับให้คุณเขียนโค้ดอย่างที่ควรจะเป็น สำหรับบทความที่สมบูรณ์ยิ่งขึ้นเกี่ยวกับแนวคิดนี้โปรดดูโพสต์ของฉัน:
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับข้อกังวลบางประการที่เกี่ยวข้องกับเฟรมเวิร์กปลอมโปรดดูที่โพสต์เหล่านี้:
หากคุณสนใจที่จะเรียนรู้ RhinoMocks นี่คือวิดีโอฝึกอบรม Pluralsight (การเปิดเผยแบบเต็ม - ฉันเขียนหลักสูตรนี้และได้รับค่าลิขสิทธิ์สำหรับการดู แต่ฉันคิดว่ามันใช้ได้กับการสนทนานี้ดังนั้นฉันจึงรวมไว้ที่นี่):