Dans l'exemple de code suivant, j'ai une classe Async Calculator. Ceci est injecté avec un ICalc, qui sera une calculatrice syncroneuse. J'utilise l'injection de dépendances et je me moque de l'ICalc parce que cela ressemble à mon vrai scénario, bien que je suppose que le moqueur n'est pas vraiment pertinent pour la question. L'AsyncCalc a une fonction qui appellera une autre fonction de manière asynchrone - en prenant un callback comme paramètre. Et lorsque l'appel de fonction async se termine, le rappel sera déclenché avec le résultat.Fonction de test unitaire asynchrone
Maintenant je veux tester ma fonction asynchrone - vérifier que le rappel est déclenché avec le paramètre attendu. Ce code semble fonctionner. Cependant, j'ai l'impression que ça pourrait exploser à tout moment - et je m'inquiète de la condition de course du rappel pour terminer avant que la fonction ne se termine et que le test soit terminé - car cela se déroulera dans un fil séparé.
Ma question est maintenant de savoir si je suis sur la bonne unité de test de la fonction asynchrone, ou si quelqu'un peut m'aider à prendre la bonne voie ..? Qu'est-ce qui se sentirait mieux, c'est si je pouvais m'assurer que le rappel est déclenché tout de suite - et de préférence sur le même fil, je suppose? Peut/Devrait-il être fait?
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);
}
Je pense que votre test aurait simplement d'attendre dans une boucle jusqu'à ce que le rappel exécute. –