8
votes

Comment Test d'unité Begininvoke sur une action

Je cherche un moyen de tester BeginInvoke sur une méthode d'action, car la méthode fonctionne sur un fil d'arrière-plan, il n'ya aucun moyen de savoir quand elle complète ou appelle la méthode de rappel. Je cherche un moyen de garder mon test attendre jusqu'à ce que le rappel soit appelé avant de faire des affirmations.

Dans la classe de présentatrice suivante, vous pouvez remarquer que j'appellerais PopulateView sur le thread d'arrière-plan qui met à jour la vue lorsque les données sont récupérées et que j'essaie d'affirmer que les propriétés d'affichage sont correctement initialisées. p>

J'utilise Nunit et MOQ. P>

public class Presenter
{
    private IView _view;
    private IService _service;
    public Presenter(IView view, IService service)
    {
        _view = view;
        _service = service;

        Action action = PopulateView;  
        action.BeginInvoke(PopulateViewCallback, action);
    }
    private void PopulateViewCallback(IAsyncResult ar)
    {
            try
            {
                Action target = (Action)ar.AsyncState;
                target.EndInvoke(ar);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogException("Failed to initialize view", ex);
            }
    }

     private void PopulateView()
     {
          Thread.Sleep(2000); // Fetch data _service.DoSomeThing()
          _view.Property1 = "xyz";
     }  
}


0 commentaires

3 Réponses :


2
votes

beginInvoke () code> retourne un IAsyncresult code> que vous pouvez utiliser pour attendre.

IAsynchResult ar = action.BeginInvoke(...);
ar.AsyncWaitHandle.WaitOne();


4 commentaires

Comment puis-je saisir IAsynchResult (AR)?


C'est la valeur de retour de Begininvoke. Vous pouvez voir que dans le code.


J'appuie du constructeur et je n'y ai pas accès à l'extérieur de la classe pour écrire des tests d'unité.


Parfois, il vous suffit de refacturer votre code pour le rendre testable



0
votes

Vous n'avez pas besoin de vérifier que les méthodes sont appelées à la place, testez le résultat final - dans ce cas que _view.propert1 == "xyz".

Parce que c'est un appel ASYNC, vous devrez peut-être avoir une boucle qui affirme périodiquement que la valeur a été définie, également un délai d'attente sur le test ou le chèque est un contraire, sinon votre test ne manquerait jamais (juste bloqué).

Vous pouvez envisager de sortir de l'action (populationview) afin de sauter le sommeil.


0 commentaires

9
votes

Résumé Votre code afin que vous puissiez injecter le comportement que vous souhaitez au moment de l'essai. XXX

Cette version est asynchrone. Au moment de l'essai, vous pouvez simplement créer une version de blocage: xxx

puis votre code passe simplement à ce code: xxx

Au moment de l'exécution, c'est asynchrone. Au moment des tests, il bloque l'appel.


3 commentaires

Cela semble bien, en avez pensé et peut l'utiliser pour le nouveau code, mais comment est-ce que l'unité teste le code existant qui appelle DébutInvoke directement.


Refacteur? La dépendance existe là-bas; Le seul moyen de tester un appareil est de le résumé ou de ne pas le tester. = /


Le paramètre Callback doit être de type asynccallback. Mais merci, c'est génial :)