Testy z nunit

Zaczynam od TDD i sam mogę rozwiązać większość problemów, z którymi się borykałem. Ale teraz jestem zagubiony: jak mogę sprawdzić, czy zdarzenia są zwolnione? Szukałem czegoś w stylu Assert.Raise LUB Assert.Fire, ale nic nie ma. Google nie było zbyt przydatne, większość trafień były sugestie jak foo.myEvent += new EventHandler(bar); Assert.NotNull(foo.myEvent);, ale to niczego nie dowodzi.

Dziękuję!
Author: jdhurst, 2010-08-02

9 answers

Sprawdzenie, czy zdarzenia zostały wywołane, można wykonać zapisując się do tego zdarzenia i ustawiając wartość logiczną:

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

...

Assert.IsTrue(wasCalled);

Z powodu prośby - BEZ lambda:

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

...

Assert.IsTrue(wasCalled);
 52
Author: Dror Helper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-03 17:04:59

Wolę robić co następuje:

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

Zalety: obsługuje scenariusz wielowątkowy (jeśli handler jest wywoływany w innym wątku)

 17
Author: aderesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 11:49:14

Jeśli wiesz, że zdarzenie zostanie wywołane synchronicznie:

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

customer.Name = "Sam";

Assert.IsTrue(eventRaised);

Jeżeli zdarzenie może być wywołane asynchronicznie:

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));

Jednak niektórzy twierdzą, że należy unikać testowania asynchronicznego zachowania.

 12
Author: Clay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 18:11:49

Ostatnio musiałem to zrobić, a poniżej jest to, co wymyśliłem. Powodem, dla którego nie zrobiłem tego, co mówili inni posty, jest to, że nie podoba mi się idea zmiennej utrzymanie stanu i konieczności resetowania go "ręcznie" między wieloma zdarzeniami.

Poniżej znajduje się kod zdarzenia ClassUnderTest z NameChanged, które jest testowane wMyTests testach:

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);
    }
}

Klasy pomocnicze są poniżej. Klasy mogą być używane z dowolnymi EventHandler<TEventArgs> lub rozszerzane na inne delegaty. Testy zdarzeń mogą być zagnieżdżane.

/// <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));
        };
    }
}
 5
Author: earlNameless,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-17 17:49:47

Używając NUnit i Moq możesz wykonać bardziej solidne testowanie zdarzeń.

Klasa Mocka używana do monitorowania wyzwalaczy zdarzeń:

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

Konfiguracja wyzwalaczy zdarzeń:

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

Używanie Mock obiektów w testach:

[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);

}
 3
Author: Greg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-15 04:03:54

Nie zrobiłem tego osobiście, ale może mógłbyś dodać atrapę obsługi zdarzenia do zdarzenia, które chcesz subskrybować i poprosić go o aktualizację lokalnej zmiennej logicznej, aby po wywołaniu metody można było sprawdzić stan tego zdarzenia logicznego, aby zobaczyć, czy zdarzenie zostało wywołane?

Coś w stylu:

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

Assert.IsTrue(eventFired);
 1
Author: theburningmonk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-02 11:16:00

@theberningmonk: brakuje";". Poprawiona wersja to:

bool eventFired = false;
foo.MyEvent += (s, e) => { eventFired = true; };
Assert.IsTrue(eventFired);
Zdrówko! ;-)
 1
Author: Manfred,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-02 11:51:20

Użyłbym FluentAssertions razem z Nunit : https://fluentassertions.com/eventmonitoring to działa naprawdę dobrze. Oto przykład z docs

var subject = new EditCustomerViewModel();
using (var monitoredSubject = subject.Monitor())
{
    subject.Foo();
    monitoredSubject.Should().Raise("NameChangedEvent");
}
 1
Author: sacha barber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-11 11:00:07

Możesz dodać niestandardową obsługę zdarzeń, która na przykład zwiększa pole integer w klasie przypadków testowych. A następnie sprawdź, czy pole zostało zwiększone.

 0
Author: DixonD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-02 11:14:21