2010-08-02 6 views
29

Je ne fais que commencer avec TDD et je pourrais résoudre la plupart des problèmes que j'ai rencontrés par moi-même. Mais maintenant je suis perdu: Comment puis-je vérifier si les événements sont déclenchés? Je cherchais quelque chose comme Assert.Raise ou Assert.Fire mais il n'y a rien. Google n'était pas très utile, la plupart des hits étaient des suggestions comme foo.myEvent += new EventHandler(bar); Assert.NotNull(foo.myEvent); mais cela ne prouve rien.Evénements de test avec nunit

Merci!

Répondre

40

Vérifier si les événements ont été tirés qui peut être fait en vous inscrivant à cet événement et définir une valeur booléenne:

var wasCalled = false; 
foo.NyEvent += (o,e) => wasCalled = true; 

... 

Assert.IsTrue(wasCalled); 

En raison de la demande - sans lambdas:

var wasCalled = false; 
foo.NyEvent += delegate(o,e){ wasCalled = true;} 

... 

Assert.IsTrue(wasCalled); 
0

Vous pouvez ajouter votre gestionnaire d'événements personnalisé qui, par exemple, incrémente un champ d'entier dans la classe de scénario de test. Et puis vérifiez si le champ a été incrémenté.

1

Pas vraiment fait moi-même, mais peut-être pourriez-vous ajouter un gestionnaire d'événement fictif à l'événement auquel vous voulez vous abonner et lui demander de mettre à jour une variable booléenne locale pour que, après le déclenchement de la méthode, vous vérifiiez l'état de ce booléen?

Quelque chose comme:

bool eventFired = false; 
foo.MyEvent += (s, e) => { eventFired = true }; 

Assert.IsTrue(eventFired); 
1

@theburningmonk: A ";" est manquant. La version corrigée est:

bool eventFired = false; 
foo.MyEvent += (s, e) => { eventFired = true; }; 
Assert.IsTrue(eventFired); 

Cheers! ;-)

+0

bonne prise! Je mettrais à jour ma réponse mais il n'y a pas grand chose à dire car c'est vraiment une dup de la réponse de Dror de toute façon – theburningmonk

5

J'ai récemment dû faire ceci, et voici ce que j'ai trouvé. La raison pour laquelle je n'ai pas fait ce que disaient les autres posts, c'est que je n'aime pas l'idée d'un état de conservation des variables et de devoir le réinitialiser "manuellement" entre plusieurs événements.

est Ci-dessous le code de l'événement avec ClassUnderTestNameChanged qui est testé dans MyTests essais:

public class ClassUnderTest { 
    private string name; 
    public string Name { 
     get { return this.name; } 
     set { 
      if (value != this.name) { 
       this.name = value; 
       NameChanged(this, new PropertyChangedEventArgs("Name")); 
      } 
     } 
    } 

    public event EventHandler<PropertyChangedEventArgs> NameChanged = delegate { }; 
} 

[TestFixture] 
public class MyTests { 
    [Test] 
    public void Test_SameValue() { 
     var t = new ClassUnderTest(); 
     var e = new EventHandlerCapture<PropertyChangedEventArgs>(); 
     t.NameChanged += e.Handler; 

     Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(),() => t.Name = null); 
     t.Name = "test"; 
     Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(),() => t.Name = "test"); 
    } 
    [Test] 
    public void Test_DifferentValue() { 
     var t = new ClassUnderTest(); 
     var e = new EventHandlerCapture<PropertyChangedEventArgs>(); 
     t.NameChanged += e.Handler; 

     Event.Assert(e, Event.IsPropertyChanged(t, "Name"),() => t.Name = "test"); 
     Event.Assert(e, Event.IsPropertyChanged(t, "Name"),() => t.Name = null); 
    } 
} 

Les classes de soutien sont ci-dessous. Les classes peuvent être utilisées avec n'importe quel EventHandler<TEventArgs> ou étendues à d'autres délégués. Les tests d'événement peuvent être imbriqués.

/// <summary>Class to capture events</summary> 
public class EventHandlerCapture<TEventArgs> where TEventArgs : EventArgs { 
    public EventHandlerCapture() { 
     this.Reset(); 
    } 

    public object Sender { get; private set; } 
    public TEventArgs EventArgs { get; private set; } 
    public bool WasRaised { get; private set; } 

    public void Reset() { 
     this.Sender = null; 
     this.EventArgs = null; 
     this.WasRaised = false; 
    } 

    public void Handler(object sender, TEventArgs e) { 
     this.WasRaised = true; 
     this.Sender = sender; 
     this.EventArgs = e; 
    } 
} 

/// <summary>Contains things that make tests simple</summary> 
public static class Event { 
    public static void Assert<TEventArgs>(EventHandlerCapture<TEventArgs> capture, Action<EventHandlerCapture<TEventArgs>> test, Action code) where TEventArgs : EventArgs { 
     capture.Reset(); 
     code(); 
     test(capture); 
    } 
    public static Action<EventHandlerCapture<TEventArgs>> IsNotRaised<TEventArgs>() where TEventArgs : EventArgs { 
     return (EventHandlerCapture<TEventArgs> test) => { 
      NUnit.Framework.Assert.That(test.WasRaised, Is.False); 
     }; 
    } 
    public static Action<EventHandlerCapture<PropertyChangedEventArgs>> IsPropertyChanged(object sender, string name) { 
     return (EventHandlerCapture<PropertyChangedEventArgs> test) => { 
      NUnit.Framework.Assert.That(test.WasRaised, Is.True); 
      NUnit.Framework.Assert.That(test.Sender, Is.SameAs(sender)); 
      NUnit.Framework.Assert.That(test.EventArgs.PropertyName, Is.EqualTo(name)); 
     }; 
    } 
} 
8

Si vous connaissez l'événement sera tiré de façon synchrone:

bool eventRaised = false; 
Customer customer = new Customer() { Name = "Carl" }; 
customer.NameChanged += (sender, e) => { eventRaised = true; }; 

customer.Name = "Sam"; 

Assert.IsTrue(eventRaised); 

Si l'événement peut être tiré de manière asynchrone:

ManualResetEvent eventRaised = new ManualResetEvent(false); 
Customer customer = new Customer() { Name = "Carl" }; 
customer.NameChanged += (sender, e) => { eventRaised.Set(); }; 

customer.Name = "Sam"; 

Assert.IsTrue(eventRaised.WaitOne(TIMEOUT)); 

Cependant, certains disent tester le comportement asynchrone devrait être évité.

6

Je préfère faire comme suit:

var wait = new AutoResetEvent(false); 
foo.MeEvent += (sender, eventArgs) => { wait.Set(); }; 
Assert.IsTrue(wait.WaitOne(TimeSpan.FromSeconds(5))); 

Avantages: Prise en charge de scénario de multithreading (si gestionnaire est appelé à thread différent)

+0

Je prends une approche similaire mais préfère 'ManualResetEvent'. – Oliver

0

En utilisant NUnit et Moq vous pouvez faire des tests d'événements plus robuste.

Mock classe utilisé pour surveiller les déclencheurs d'événements:

public class AssertEvent { public virtual void Call(string obj) { } } 
Mock<AssertEvent> EventMock; 
AssertEvent Evt; 

Configuration pour l'événement Triggers:

[SetUp] 
public void TestInit() { 
    EventMock = new Mock<AssertEvent>(); 
    Evt= EventMock.Object; 
} 

Utilisation d'objets simulés dans les essais:

[Test] 
public void TestMethod() { 
    myObject.Event1 += (sender, args) => Evt.Call("Event1Label"); 
    myObject.Event2 += (sender, args) => Evt.Call("Event2Label"); 
    myObject.Event3 += (sender, args) => Evt.Call("Event3Label");   

    myObject.SomeEventTrigger(); 

    EventMock.Verify(m => m.Call("Event1Label"), Times.Exactly(1)); 
    EventMock.Verify(m => m.Call("Event2Label"), Times.Never()); 
    EventMock.Verify(m => m.Call("Event3Label"), Times.Between(1,3); 

} 
Questions connexes