Come testare gli eventi

event

Testare che degli eventi siano stato effettivamente lanciati in C# non è immediato.

Tipicamente è possibile testare che un evento venga lanciato aspettando un ManualResetEvent che viene settato in un listener dell’evento stesso.

Questo metodo funziona ma risulta un po’ macchinoso; Fluent Assertion risolve il problema fornendo dei metodi comodi per testare il tutto.

Fluent Assertion

Fluent Assertion permette di testare che un determinato evento venga lanciato in modo semplice.

Per prima cosa è necessario comunicare a Fluent Assertion che voglio monitorare l’oggetto utilizzando il l’extension Monitor();

using var monitoredClass = _myClass.Monitor();

e successivamente è possibile utilizzare il check Should().Raise("EventName") in questo modo:

monitoredClass.Should().Raise(nameof(myClass.MyCustomEvent));

E’ possibile anche aggiungere dei check sul sender e sugli args in questo modo:

monitoredClass.Should()
            .Raise(nameof(myClass.MyCustomEvent))
            .WithSender(subject)
            .WithArgs<PropertyChangedEventArgs>(args => args.PropertyName == "SomeProperty");

Esempio completo

Di seguito un esempio completo di una classe di test per gli eventi.

using System;
using FluentAssertions;
using Xunit;

namespace Tests;

public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string param)
    {
        Param = param;
    }

    public string Param { get; }
}

public class ClassToTest
{
    public void MethodThatRaisesEvent()
    {
        // Do something
        RaiseMyCustomEventEvent();
        // Do something else
    }

    public void MethodThatRaisesEventWithArgs(string arg)
    {
        // Do something
        RaiseMyCustomEventWithArgsEvent(arg);
        // Do something else
    }

    public static void MethodThatDoNotRaiseEvent()
    {
        // Do nothing
    }

    #region MyCustomEvent

    public delegate void MyCustomEventEventHandler(object sender, EventArgs e);

    public event MyCustomEventEventHandler MyCustomEvent;

    private void RaiseMyCustomEventEvent()
    {
        MyCustomEvent?.Invoke(this, EventArgs.Empty);
    }

    #endregion

    #region MyCustomEventWithArgs

    public delegate void MyCustomEventWithArgsEventHandler(object sender, CustomEventArgs e);

    public event MyCustomEventWithArgsEventHandler MyCustomEventWithArgs;

    private void RaiseMyCustomEventWithArgsEvent(string arg)
    {
        MyCustomEventWithArgs?.Invoke(this, new CustomEventArgs(arg));
    }

    #endregion
}

public class TesterClass
{
    private readonly ClassToTest _myClass = new();

    [Fact]
    public void TestEventIsRaised()
    {
        using var monitoredClass = _myClass.Monitor();
        _myClass.MethodThatRaisesEvent();
        monitoredClass.Should().Raise(nameof(ClassToTest.MyCustomEvent));
    }

    [Fact]
    public void TestEventAndArgsIsRaised()
    {
        const string arg = "foo";
        using var monitoredClass = _myClass.Monitor();
        _myClass.MethodThatRaisesEventWithArgs(arg);
        monitoredClass.Should().Raise(nameof(ClassToTest.MyCustomEventWithArgs))
            .WithSender(_myClass)
            .WithArgs<CustomEventArgs>(args => args.Param == arg);
    }

    [Fact]
    public void TestEventIsNotRaised()
    {
        using var monitor = _myClass.Monitor();
        ClassToTest.MethodThatDoNotRaiseEvent();
        monitor.Should().NotRaise(nameof(ClassToTest.MyCustomEvent));
    }
}

Indice

Share
Ultimi articoli
Join

Newsletter

Nessuno spam, solo articoli interessanti ;)

Focus

Post correlati

semaphoreslim

SmaphoreSlim 101

SemaphoreSlim è una classe che permette la sincronizzazione di n thread che hanno una risorsa (scarsa) condivisa limitandone l’uso ad un numero massimo.

interlocked

Interlocked 101

La sincronizzazione dei thread è un elemento fondamentale nella programmazione asincrona, ne ho infatti parlato in vari post. La soluzione più versatile è sicuramente utilizzare

md5

Perché non dovresti usare MD5

Introduzione Le funzioni di hash permettono di ottenere una sequenza di bit tramite l’utilizzo di funzioni matematiche in base ai dati in ingresso; la loro

Codice Pragmatico

Contatti

Per informazioni, dubbi o consulenze non esitate a contattarmi.

Lascia un messaggio

Ricevi le ultime news

Iscrivi alla newsletter

Solo articoli interessanti, promesso ;)