2017-05-10 5 views
0

Supposons que j'ai une simple classe Api comme celui-ci, où un appel externe est fait, mais une exception est levée au bout de 5 secondes si elle ne se termine pas:C# - Test pour affirmer les temps de composants après X secondes

public class Api 
{ 
    private readonly IConnector connector; 

    public Api(IConnector connector) 
    { 
     this.connector = connector; 
    } 

    public string GetSomething() 
    { 
     var timer = new System.Timers.Timer(5000); 
     timer.Elapsed += TimeOut; 

     timer.Start(); 
     //some external call which takes time 
     connector.Retrieve(); 
     timer.Stop(); 

     return "Something"; 
    } 

    private void TimeOut(object sender, ElapsedEventArgs e) 
    { 
     throw new TimeoutException("Timed out!"); 
    } 
} 

En utilisant NUnit ou autre, comment pourrais-je tester si ce qui précède génère une exception quand la requête prend 8 secondes, mais réussit quand la requête prend 3 secondes?

J'ai essayé le ci-dessous:

[TestFixture] 
public class ApiTests 
{ 
    IConnector mockConnector; 
    Api api; 

    [SetUp] 
    public void Setup() 
    { 
     mockConnector = MockRepository.GenerateMock<IConnector>(); 
     api = new Api(mockConnector); 
    } 

    [Test] 
    public void Api_RetrieveTakes3Seconds_SomethingReturned() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(3000).ContinueWith(c => "Something").Result); 
     var response = api.GetSomething(); 

     Assert.AreEqual("Something", response); 
    } 

    [Test] 
    public void Api_RetrieveTakes8Seconds_TimeOutExceptionThrown() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(8000).ContinueWith(c => "Something").Result); 
     var response = api.GetSomething(); 

     //assert an exception is thrown on the above 
    } 

} 

Mais cela ne fonctionne pas comme prévu, quand je déboguer la tâche attend juste sur la ligne de bout pendant X secondes (avant api.GetSomething() est même appelé)

Comment puis-je ajuster ces tests pour obtenir le comportement souhaité?

En bonus, ce serait génial s'il était possible de ne pas avoir à attendre l'exécution des silences.

+0

peut-être essayer "mockConnector.Stub (c => c.Retrieve()). Retour (() => Task.Delay (3000) .ContinueWith (c =>" Quelque chose "). Résultat);" pour obtenir votre code d'attente sur la bonne ligne? – JBdev

Répondre

0

Vous pouvez tester une exception avec les « Assert.Throws » nunit assert.You peut tester qu'une valeur est retournée après quantité x de temps en utilisant un chronomètre comme ceci:

[Test] 
    public void Api_RetrieveTakes3Seconds_SomethingReturned() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(3000).ContinueWith(c => "Something").Result); 
     topwatch sw = new Stopwatch(); 
     sw.Start(); 
     var response = api.GetSomething(); 
     sw.Stop(); 
     Assert.That(sw.ElapsedMilliseconds, Is.LessThanOrEqualTo(3000));  } 

    [Test] 
    public void Api_RetrieveTakes8Seconds_TimeOutExceptionThrown() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(8000).ContinueWith(c => "Something").Result); 

     Assert.Throws(Exception,()=> api.GetSomething()); 
    } 

Vous devrez ajoutez un peu de tampon puisque votre test attend exactement 3 secondes, donc vous devriez probablement vérifier que le test revient en moins de 3,1 secondes ou quelque chose comme ça.

+0

Hmm mais cela semble souffrir du même problème, le retard artificiel ne se produit pas lorsque Retrieve() est appelé sur le talon - cela arrive juste quand le talon est créé. L'appel Retrieve() est toujours instantané. – FBryant87

0

Pour le chemin heureux, essayez

Assert.That(() => api.GetSomething(), Is.EqualTo(expected).After(3).Seconds)); 

Vous devrez peut-être ajuster le temps qu'il est soumis à la latence.

Pour l'échec, vous avez besoin d'une injection d'une maquette ou faux dans api qui prend trop de temps et puis ...

Assert.That(() => api.GetSomething(), Throws.Typeof<MyException>()); 

C'est tout le code forum, alors faites attention des erreurs. :-)

+0

Merci, cependant, cela rend le faux bouchon de Retrieve() trop long, ce qui pose problème. Comment cela peut-il être fait? – FBryant87

+0

Pas un gars Rhino, mais je pense que d'autres réponses vous disent comment faire cela. – Charlie