ฉันจะบอก Moq ให้ส่งคืนภารกิจได้อย่างไร


327

ฉันมีอินเตอร์เฟซที่ประกาศ

Task DoSomethingAsync();

ฉันใช้ MoqFramework สำหรับการทดสอบ:

[TestMethod()]
public async Task MyAsyncTest()
{
   Mock<ISomeInterface> mock = new Mock<ISomeInterface>();
   mock.Setup(arg => arg.DoSomethingAsync()).Callback(() => { <my code here> });
   ...
}

await DoSomethingAsync()จากนั้นในการทดสอบของฉันฉันรันโค้ดที่จะเรียก และการทดสอบล้มเหลวในบรรทัดนั้น ผมทำอะไรผิดหรือเปล่า?


5
เมื่อคุณพูดว่าข้อผิดพลาดในการทดสอบในบรรทัดนั้นมันเกิดข้อผิดพลาดอะไร
AlSki

@AlSki สนับสนุน NullReferenceException อย่างที่คุณเห็นนี่
LuckyLikey

คำตอบ:


709

วิธีการของคุณไม่ได้มีการเรียกกลับใด ๆ .CallBack()ดังนั้นจึงไม่มีเหตุผลที่จะใช้ไม่ได้ คุณสามารถคืนภารกิจด้วยค่าที่ต้องการโดยใช้.Returns()และTask.FromResultเช่น:

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.FromResult(someValue));

อัปเดต 2014-06-22

Moq 4.2 มีวิธีการขยายสองวิธีใหม่เพื่อช่วยในเรื่องนี้

mock.Setup(arg=>arg.DoSomethingAsync())
    .ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .ThrowsAsync(new InvalidOperationException());

อัพเดท 2016-05-05

ในฐานะที่เป็นเซทดอกไม้กล่าวถึงในคำตอบอื่น ๆ , จะใช้ได้เฉพาะวิธีการที่ผลตอบแทนReturnsAsync Task<T>สำหรับวิธีการที่คืนค่าเฉพาะภารกิจ

.Returns(Task.FromResult(default(object)))

สามารถใช้ได้.

ดังที่แสดงในคำตอบนี้ใน. NET 4.6 จะทำให้ง่าย.Returns(Task.CompletedTask);ขึ้นเช่น:

mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.CompletedTask);

16
.Returns (Task.CompletedTask); นั่นคือคำตอบของฉัน
ทอดด์แวนซ์

8
ขอบคุณสำหรับการรักษาคำตอบนี้เป็นกรอบ Moq ได้รับการปรับปรุง!
Jacob Stamm

.Returns(Task.FromResult(default(object))ทำงานได้ดีเมื่อชนิดส่งคืนเป็นโมฆะ .Returns(Task.FromResult(null as MyType))ทำงานได้ดีเมื่อชนิดส่งคืนที่คาดไว้เป็นโมฆะ
เจเรมีเรย์บราวน์

1
@ JeremyRayBrown ตามที่ฉันอธิบายใน. NET 4.6 default(object)ไม่จำเป็นอีกต่อไป null as MyTypeเหมือนกับdefault(MyType)ตราบใดที่MyTypeเป็นประเภทการอ้างอิง
Panagiotis Kanavos

40

ปัญหาที่คล้ายกัน

ฉันมีอินเทอร์เฟซที่ดูประมาณ:

Task DoSomething(int arg);

อาการ

ทดสอบหน่วยของฉันล้มเหลวเมื่อบริการของฉันภายใต้การทดสอบสายไปawaitedDoSomething

แก้ไข

ซึ่งแตกต่างจากคำตอบที่ได้รับการยอมรับคุณไม่สามารถที่จะเรียก.ReturnsAsync()บนSetup()ของวิธีการนี้ในสถานการณ์นี้เพราะวิธีการที่จะส่งกลับไม่ใช่ทั่วไปมากกว่าTaskTask<T>

อย่างไรก็ตามคุณยังสามารถใช้งาน.Returns(Task.FromResult(default(object)))การตั้งค่าเพื่อให้การทดสอบผ่านได้


1
แค่คิดเกี่ยวกับเรื่องนี้ถ้าคุณต้องการส่งคืนงานที่ไม่ใช่ทั่วไป (ไม่ใช่. net 4.6) ฉันจะพิจารณากลับ TaskDelay (1) เป็นวิธีที่ง่ายในการคืนภารกิจ นอกจากนี้คุณยังสามารถเลียนแบบการทำงานด้วยโดยเพิ่มอาร์กิวเมนต์เวลา
stevethethread

26

คุณจะต้องเพิ่ม.Returns(Task.FromResult(0));หลังจากโทรกลับ

ตัวอย่าง:

mock.Setup(arg => arg.DoSomethingAsync())
    .Callback(() => { <my code here> })
    .Returns(Task.FromResult(0));

4

ตอนนี้คุณสามารถใช้แพ็คเกจ Talentsoft.Moq.SetupAsync https://github.com/TalentSoft/Moq.SetupAsync

ซึ่งบนพื้นฐานของคำตอบที่พบที่นี่และแนวคิดที่เสนอให้ Moq แต่ยังไม่ได้ดำเนินการที่นี่: https://github.com/moq/moq4/issues/384ทำให้การติดตั้ง async ทำได้ง่ายขึ้นมาก

พบตัวอย่างไม่กี่ตัวอย่างในการตอบกลับก่อนหน้าด้วยนามสกุล SetupAsync

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.