ठीक है - मुझे यकीन नहीं है कि निम्न में से कोई भी आपकी मदद करेगा, क्योंकि मैंने एक समाधान विकसित करने में कुछ धारणाएं बनाई हैं जो आपके मामले में सच हो सकती हैं या नहीं। शायद मेरा "समाधान" बहुत सैद्धांतिक है और केवल कलात्मक उदाहरणों के लिए काम करता है - मैंने नीचे के सामान से परे कोई परीक्षण नहीं किया है।
इसके अलावा, मैं एक वास्तविक समाधान की तुलना में निम्नलिखित अधिक वैकल्पिक हल देखूंगा, लेकिन प्रतिक्रियाओं की कमी को देखते हुए मुझे लगता है कि यह अभी भी कुछ भी नहीं से बेहतर हो सकता है (मैं आपके प्रश्न को एक समाधान के लिए इंतजार कर रहा देखता रहा, लेकिन एक पोस्ट किए जाने को देखते हुए मैंने खेलना शुरू नहीं किया मुद्दे के साथ आसपास)।
लेकिन पर्याप्त कहा: मान लें कि हमारे पास एक सरल डेटा सेवा है जिसका उपयोग पूर्णांक प्राप्त करने के लिए किया जा सकता है:
public interface IDataService
{
Task<int> LoadMagicInteger();
}
एक साधारण कार्यान्वयन अतुल्यकालिक कोड का उपयोग करता है:
public sealed class CustomDataService
: IDataService
{
public async Task<int> LoadMagicInteger()
{
Console.WriteLine("LoadMagicInteger - 1");
await Task.Delay(100);
Console.WriteLine("LoadMagicInteger - 2");
var result = 42;
Console.WriteLine("LoadMagicInteger - 3");
await Task.Delay(100);
Console.WriteLine("LoadMagicInteger - 4");
return result;
}
}
अब, एक समस्या उत्पन्न होती है, अगर हम इस वर्ग के अनुसार "गलत तरीके से" कोड का उपयोग कर रहे हैं। आईएनजी परिणाम के बजाय Foo
गलत तरीके से पहुंचता है:Task.Result
await
Bar
public sealed class ClassToTest
{
private readonly IDataService _dataService;
public ClassToTest(IDataService dataService)
{
this._dataService = dataService;
}
public async Task<int> Foo()
{
var result = this._dataService.LoadMagicInteger().Result;
return result;
}
public async Task<int> Bar()
{
var result = await this._dataService.LoadMagicInteger();
return result;
}
}
हमें (आपको) अब एक परीक्षण लिखने का एक तरीका है जो कॉल करते समय सफल होता है Bar
लेकिन कॉल करते समय विफल हो जाता हैFoo
(कम से कम अगर मैं प्रश्न सही ढंग से ;-))।
मैं कोड बोलने दूँगा; यहाँ मैं क्या कर रहा था (विज़ुअल स्टूडियो परीक्षणों का उपयोग करके, लेकिन यह NUnit का उपयोग करके भी काम करना चाहिए):
DataServiceMock
उपयोग करता है TaskCompletionSource<T>
। यह हमें परीक्षण रन में एक परिभाषित बिंदु पर परिणाम निर्धारित करने की अनुमति देता है जो निम्न परीक्षण की ओर जाता है। ध्यान दें कि हम TaskCompletionSource को वापस परीक्षण में पास करने के लिए एक प्रतिनिधि का उपयोग कर रहे हैं। आप इसे परीक्षण की प्रारंभिक विधि में भी डाल सकते हैं और गुणों का उपयोग कर सकते हैं।
TaskCompletionSource<int> tcs = null;
this._dataService.LoadMagicIntegerMock = t => tcs = t;
Task<int> task = null;
TaskTestHelper.AssertDoesNotBlock(() => task = this._instance.Foo());
tcs.TrySetResult(42);
var result = task.Result;
Assert.AreEqual(42, result);
this._end = true;
यहां क्या हो रहा है कि हम पहले यह सत्यापित करते हैं कि हम विधि को अवरुद्ध किए बिना छोड़ सकते हैं (यह काम नहीं करेगा यदि कोई एक्सेस करता है Task.Result
- इस मामले में हम एक टाइमआउट में भाग लेंगे क्योंकि कार्य का परिणाम उपलब्ध नहीं है जब तक कि विधि वापस नहीं आई है। )।
फिर, हम परिणाम सेट करते हैं (अब विधि निष्पादित कर सकते हैं) और हम परिणाम को सत्यापित करते हैं (एक इकाई परीक्षण के अंदर हम टास्क तक पहुंच सकते हैं। परिणाम के रूप में हम वास्तव में अवरुद्ध होने के लिए चाहते हैं)।
पूर्ण परीक्षण वर्ग - BarTest
सफल और FooTest
वांछित के रूप में विफल रहता है।
[TestClass]
public class UnitTest1
{
private DataServiceMock _dataService;
private ClassToTest _instance;
private bool _end;
[TestInitialize]
public void Initialize()
{
this._dataService = new DataServiceMock();
this._instance = new ClassToTest(this._dataService);
this._end = false;
}
[TestCleanup]
public void Cleanup()
{
Assert.IsTrue(this._end);
}
[TestMethod]
public void FooTest()
{
TaskCompletionSource<int> tcs = null;
this._dataService.LoadMagicIntegerMock = t => tcs = t;
Task<int> task = null;
TaskTestHelper.AssertDoesNotBlock(() => task = this._instance.Foo());
tcs.TrySetResult(42);
var result = task.Result;
Assert.AreEqual(42, result);
this._end = true;
}
[TestMethod]
public void BarTest()
{
TaskCompletionSource<int> tcs = null;
this._dataService.LoadMagicIntegerMock = t => tcs = t;
Task<int> task = null;
TaskTestHelper.AssertDoesNotBlock(() => task = this._instance.Bar());
tcs.TrySetResult(42);
var result = task.Result;
Assert.AreEqual(42, result);
this._end = true;
}
}
और गतिरोध / टाइमआउट के लिए परीक्षण करने के लिए एक छोटा सहायक वर्ग:
public static class TaskTestHelper
{
public static void AssertDoesNotBlock(Action action, int timeout = 1000)
{
var timeoutTask = Task.Delay(timeout);
var task = Task.Factory.StartNew(action);
Task.WaitAny(timeoutTask, task);
Assert.IsTrue(task.IsCompleted);
}
}
async
लेखों का संग्रह पढ़ा है ?