ใช้ Moq และดูCallback
แต่ฉันไม่สามารถหาตัวอย่างง่ายๆเพื่อทำความเข้าใจวิธีการใช้งานได้
คุณมีตัวอย่างข้อมูลการทำงานขนาดเล็กที่อธิบายอย่างชัดเจนว่าจะใช้อย่างไรและเมื่อใด
ใช้ Moq และดูCallback
แต่ฉันไม่สามารถหาตัวอย่างง่ายๆเพื่อทำความเข้าใจวิธีการใช้งานได้
คุณมีตัวอย่างข้อมูลการทำงานขนาดเล็กที่อธิบายอย่างชัดเจนว่าจะใช้อย่างไรและเมื่อใด
คำตอบ:
ยากที่จะเอาชนะhttps://github.com/Moq/moq4/wiki/Quickstart
ถ้ายังไม่ชัดเจนพอฉันจะเรียกว่า doc bug ...
แก้ไข: เพื่อตอบสนองต่อคำชี้แจงของคุณ ...
สำหรับวิธีการเยาะเย้ยแต่ละวิธีที่Setup
คุณทำคุณจะต้องระบุสิ่งต่างๆเช่น:
.Callback
กลไกการบอกว่า "ฉันไม่สามารถอธิบายได้ในขณะนี้ แต่เมื่อมีการโทรที่มีรูปร่างเช่นนี้เกิดขึ้นโทรหาฉันกลับมาและฉันจะทำสิ่งที่จะต้องทำ" ในฐานะที่เป็นส่วนหนึ่งของห่วงโซ่การโทรที่คล่องแคล่วเดียวกันคุณจะควบคุมผลลัพธ์ที่จะส่งคืน (ถ้ามี) ผ่านทาง.Returns
"ในตัวอย่าง QS ตัวอย่างคือทำให้ค่าที่ส่งคืนเพิ่มขึ้นในแต่ละครั้ง
โดยทั่วไปคุณไม่จำเป็นต้องมีกลไกเช่นนี้บ่อยนัก (xUnit Test Patterns มีเงื่อนไขสำหรับการต่อต้านรูปแบบของ ilk Conditional Logic In Tests) และหากมีวิธีที่ง่ายกว่าหรือในตัวในการกำหนดสิ่งที่คุณต้องการก็ควรจะเป็น ใช้ในการตั้งค่า
ส่วนที่ 3 จาก 4 ในซีรีส์ Moq ของ Justin Etheredgeครอบคลุมและมีตัวอย่างการโทรกลับที่นี่
ตัวอย่างง่ายๆของการโทรกลับสามารถพบได้ที่การใช้การโทรกลับด้วยโพสต์Moq
Callback
ไม่มีส่วนเกี่ยวข้องกับค่าที่ส่งคืน (เว้นแต่คุณจะเชื่อมโยงผ่านโค้ด) โดยทั่วไปแล้วจะทำให้แน่ใจว่าการโทรกลับถูกเรียกก่อนหรือหลังการเรียกแต่ละครั้ง (ขึ้นอยู่กับว่าคุณผูกมัดก่อนหรือหลังReturns
ตามลำดับ) ธรรมดาและเรียบง่าย
นี่คือตัวอย่างของการใช้การโทรกลับเพื่อทดสอบเอนทิตีที่ส่งไปยังบริการข้อมูลที่จัดการการแทรก
var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;
mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1)
.Callback((DataEntity de) => insertedEntity = de);
ไวยากรณ์วิธีการทั่วไปทางเลือก:
mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1)
.Callback<DataEntity>(de => insertedEntity = de);
จากนั้นคุณสามารถทดสอบสิ่งต่างๆเช่น
Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");
It.Is<T>
ในMock.Verify
แทนเกลื่อนทดสอบด้วยอุณหภูมิ แต่ +1 เพราะฉันพนันได้เลยว่ามีคนมากมายที่จะทำงานได้ดีที่สุดจากตัวอย่าง
มีสองประเภทCallback
ใน Moq หนึ่งเกิดขึ้นก่อนการโทรกลับ อีกอันเกิดขึ้นหลังจากการโทรกลับ
var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
.Callback((x, y) =>
{
message = "Rally on!";
Console.WriteLine($"args before returns {x} {y}");
})
.Returns(message) // Rally on!
.Callback((x, y) =>
{
message = "Rally over!";
Console.WriteLine("arg after returns {x} {y}");
});
ในการโทรกลับทั้งสองครั้งเราสามารถ:
Callback
เป็นเพียงวิธีการเรียกใช้โค้ดที่กำหนดเองตามที่คุณต้องการเมื่อมีการเรียกใช้วิธีใดวิธีหนึ่งของการจำลอง นี่คือตัวอย่างง่ายๆ:
public interface IFoo
{
int Bar(bool b);
}
var mock = new Mock<IFoo>();
mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
.Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
.Returns(42);
var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);
// output:
// Bar called with: True
// Result: 42
ฉันเพิ่งพบกรณีการใช้งานที่น่าสนใจสำหรับมัน สมมติว่าคุณคาดหวังว่าจะมีการเรียกร้องให้ล้อเลียนของคุณ แต่ก็เกิดขึ้นพร้อมกัน ดังนั้นคุณจึงไม่มีทางรู้ลำดับที่พวกเขาเรียก แต่คุณต้องการทราบว่ามีการโทรที่คุณคาดไว้ (โดยไม่คำนึงถึงลำดับ) คุณสามารถทำสิ่งนี้:
var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));
// output:
// Invocations: True, False
BTW อย่าสับสนกับความแตกต่าง"ก่อนReturns
" และ "หลังReturns
" ที่ทำให้เข้าใจผิด เป็นเพียงความแตกต่างทางเทคนิคว่าโค้ดที่กำหนดเองของคุณจะทำงานหลังจากReturns
ได้รับการประเมินหรือก่อนหน้านี้ ในสายตาของผู้เรียกทั้งสองจะทำงานก่อนที่ค่าจะถูกส่งกลับ อันที่จริงหากวิธีนี้เป็นการvoid
คืนค่าคุณไม่สามารถโทรReturns
ได้ แต่ก็ยังใช้งานได้เหมือนเดิม สำหรับข้อมูลเพิ่มเติมโปรดดูที่https://stackoverflow.com/a/28727099/67824
ด้านบนของคำตอบที่ดีอื่น ๆ ที่นี่ฉันเคยใช้เพื่อแสดงตรรกะก่อนที่จะโยนข้อยกเว้น ตัวอย่างเช่นฉันต้องการจัดเก็บวัตถุทั้งหมดที่ส่งผ่านไปยังวิธีการเพื่อการตรวจสอบในภายหลังและวิธีการนั้น (ในการทดสอบบางกรณี) จำเป็นต้องทิ้งข้อยกเว้น Calling .Throws(...)
บนMock.Setup(...)
แทนที่Callback()
การกระทำและไม่เคยเรียกมันว่า อย่างไรก็ตามด้วยการทิ้งข้อยกเว้นไว้ใน Callback คุณยังคงสามารถทำสิ่งดีๆทั้งหมดที่การโทรกลับมีให้และยังคงมีข้อยกเว้น