В следующем примере кода у меня есть класс Async Calculator. Это вводится с помощью ICalc, который будет синхронным калькулятором. Я использую инъекцию зависимостей и высмеиваю ICalc, потому что это напоминает мой истинный сценарий, хотя я предполагаю, что насмешка на самом деле не имеет отношения к вопросу. AsyncCalc имеет функцию, которая будет вызывать другую функцию асинхронно - принимая обратный вызов в качестве параметра. И когда вызов асинхронной функции завершится, обратный вызов будет вызван результатом.
Теперь я хочу проверить свою асинхронную функцию - проверить, что обратный вызов вызван с ожидаемым параметром. Этот код, кажется, работает. Тем не менее, я чувствую, что он может взорваться в любое время - и меня беспокоит состояние гонки обратного вызова, которое заканчивается до завершения функции и завершения теста - так как это будет выполняться в отдельном потоке.
Теперь у меня вопрос: нахожусь ли я на правильном пути, тестирую асинхронную функцию или кто-нибудь может помочь мне встать на правильный путь? Что было бы лучше, если бы я мог гарантировать, что обратный вызов запускается сразу - и желательно в том же потоке, я думаю? Можно / нужно ли это сделать?
public interface ICalc
{
int AddNumbers(int a, int b);
}
public class AsyncCalc
{
private readonly ICalc _calc;
public delegate void ResultProcessor(int result);
public delegate int AddNumbersAsyncCaller(int a, int b);
public AsyncCalc(ICalc calc)
{
_calc = calc;
}
public void AddNumbers(int a, int b, ResultProcessor resultProcessor)
{
var caller = new AddNumbersAsyncCaller(_calc.AddNumbers);
caller.BeginInvoke(a, b, new AsyncCallback(AddNumbersCallbackMethod), resultProcessor);
}
public void AddNumbersCallbackMethod(IAsyncResult ar)
{
var result = (AsyncResult)ar;
var caller = (AddNumbersAsyncCaller)result.AsyncDelegate;
var resultFromAdd = caller.EndInvoke(ar);
var resultProcessor = ar.AsyncState as ResultProcessor;
if (resultProcessor == null) return;
resultProcessor(resultFromAdd);
}
}
[Test]
public void TestingAsyncCalc()
{
var mocks = new MockRepository();
var fakeCalc = mocks.DynamicMock<ICalc>();
using (mocks.Record())
{
fakeCalc.AddNumbers(1, 2);
LastCall.Return(3);
}
var asyncCalc = new AsyncCalc(fakeCalc);
asyncCalc.AddNumbers(1, 2, TestResultProcessor);
}
public void TestResultProcessor(int result)
{
Assert.AreEqual(3, result);
}