Test dell'abbonamento dell'handler di eventi C #

6

Voglio che i miei test di unità siano in grado di verificare che alcuni eventi siano stati sottoscritti o annullati in punti specifici. Attualmente, vedo due opzioni.

VerifiableEventHandler

Ogni cliente si abbona utilizzando la notazione comune += e -= . Ogni classe che ha un gestore di eventi verificabile deve implementare IsSubscribed (), che può interrogare l'eventhandler utilizzando GetInvocationList ().

public interface IVerifiableEventHandler<T> 
{
    event EventHandler<T> EventHandler;
    bool IsSubscribed(Delegate d);
}

// impl
public bool IsSubscribed(Delegate d)
{
    return EventHandler.GetInvocationList().Contains(d);
}

Interfaccia di abbonamento personalizzata

Il gestore di eventi C # attuale sarebbe nascosto e i clienti possono iscriversi solo utilizzando la funzione Sottoscrivi / Annulla sottoscrizione.

public interface IEventSource<T>
{
    void Subscribe(EventHandler<T> func);
    void Unsubscribe(EventHandler<T> func);
    void Raise(object sender, T event_args);
}

Pro e contras

Per me, il vantaggio del primo approccio è che il principio della sorpresa minima non viene violato. Un programmatore .Net si aspetta che gli eventi vengano sottoscritti usando la notazione += .

Il vantaggio del secondo approccio è che è molto facile da testare, poiché le funzioni non sono nulla di speciale e possono essere verificate facilmente se la classe che contiene il gestore di eventi è derisa.

C'è un modo migliore per risolvere questo problema? In caso contrario, quale delle due varianti dovrebbe essere preferita e perché?

    
posta Wilbert 15.04.2014 - 14:16
fonte

2 risposte

6

C'è una terza opzione: prendi in giro l'oggetto con l'evento e usa il test del comportamento per verificare le sottoscrizioni del mock in determinati punti. Diversi quadri di derisione lo consentono.

public interface INeedToBeMocked
{
    public event EventHandler EventRaised;
}

NSubstitute

var mockedItem = Substitute.For<INeedToBeMocked>();
mockedItem.Received().EventRaised += Arg.Any<EventHandler>();

Rhino Mocks

var mockedItem = MockRepository.GenerateMock<INeedToBeMocked>();
mockedItem.AssertWasCalled(x => x.EventRaised += Arg.Is.Anything);
    
risposta data 15.04.2014 - 19:10
fonte
3

Is there a better way to solve this problem?

Sì!

C # ti consente di eseguire l'override della sintassi += e -= . Non sono sicuro di quanto sia facile da fornire in comuni framework di derisione come Moq, ma dovrebbe essere banale creare il proprio oggetto falso che abbia dei ganci nel metodo di iscrizione e di annullamento della sottoscrizione dell'interfaccia:

    private Action foo = () => {};
    public event Action Foo
    {
        add
        {
            Console.WriteLine("Subscribe called with value: {0}", value);
            foo += value;
        }

        remove
        {
            Console.WriteLine("Unsubscribe called with value: {0}", value);
            foo -= value;
        }
    }

(anche se è probabile che tu voglia fare qualcosa di più interessante nelle proprietà)

    
risposta data 15.04.2014 - 15:01
fonte

Leggi altre domande sui tag