Utilizzo di Mock per i listener di eventi in unit test

4

Continuo a provare questo tipo di codice (lingua irrilevante):

public class Foo() {

   public Foo(IDependency1 dep1) {
      this.dep1 = dep1;
   }

   public void setUpListeners() {
      this.dep1.addSomeEventListener(.... some listener code ...);
   }
}

Tipicamente, vuoi testare cosa succede quando la dipendenza fa scattare l'evento, la classe sotto test reagisce in modo appropriato (in alcuni casi, lo scopo solo di tali classi è di collegare molti altri componenti, che può essere testato indipendentemente.

Finora, per verificarlo, finisco sempre per fare qualcosa del tipo:

  • creando uno "stub" che implementa sia un addXXXXListener , che semplicemente memorizza il callback, sia un fireXXXX , che chiama semplicemente qualsiasi listener registrato. Questo è un po 'noioso dal momento che devi creare il mock con l'interfaccia giusta, ma ciò può fare
  • usa un framework introspettivo che può 'spiare' su un metodo e iniettare la vera dipendenza nei test

C'è un modo più pulito per fare questo genere di cose?

EDIT: per chiarire cosa intendo, il mio problema è che se potessi scrivere qualcosa del genere:

public class FooTest() {

  public void testListensToDependencies() {

   IDependency mockDependency = createMock(IDependency.class)

   Foo tested = new Foo(mockDependency);
   tested.setUpListeners();

   expect(mockDependency.addSomeEventListener).toHaveBeenCalled();

  }
}

Tuttavia, ovviamente questo test dovrebbe passare indipendentemente da ciò che fa l'ascoltatore . Questo mi preoccupa, dal momento che voglio testare che sto collegando i miei oggetti per fare la cosa giusta.

La prossima cosa migliore sarebbe:

public class Foo () {

  public Foo(IDependency1 deps) { .... }

  public void setUpListeners() {

     // In a language with first class function : 
     this.dep1.addSomeEventListener(this.handleSomeEvent);       

     // In a language without it : 
     this.dep1.addSomeEventListener(new Foo.SomeEventHandler());
  }

E poi scriverei test per:

  • controlla che 'addSomeEventListener' sia stato chiamato sia con la funzione del gestore di destra, sia con un'istanza della classe del gestore di eventi di destra

  • controlla che la funzione del gestore o la classe del gestore eventi implementino effettivamente il comportamento previsto.

Ora non sono sicuro che sarebbe più chiaro, o se è il segno che sto collegando i miei oggetti nel posto sbagliato ...

    
posta phtrivier 10.10.2012 - 19:30
fonte

1 risposta

1

Quando sei unit test della classe Foo, dovresti solo andare oltre per controllare che

a) aggiungi listener è chiamato sul tuo mock e b) l'evento è attivato sul modello

Dopotutto, quando si è in fase di test di classe, non ci si deve preoccupare di ciò che la classe dipendente (Dependency1 nell'esempio) sta facendo internamente. In caso contrario, stai testando più di unità Foo. I framework di simulazione, ad esempio, Moq ti forniranno in genere un modo per affermare che un determinato metodo è chiamato sul tuo mock, puoi anche affermare il numero di volte in cui prevedi di chiamare il metodo.

qui è un esempio approssimativo usando Moq in C # (non ho compilato questo è solo per dare un'idea)

var depMock = new Mock<Dependancy1>();
var foo = new Foo(depMock.Object);
foo.setUpListeners();
//verify that addSomeEventListener was called
depMock.Verify(x=>x.addSomeEventListener);
foo.doSomethingThatShouldRaiseEvent();
//verify that event is called
depMock.Verify(x=>x.underlyingMethodOnDependency());

È il test dell'unità su Dipendenza1 che dovrebbe verificare il suo comportamento interno.

    
risposta data 24.10.2012 - 05:57
fonte

Leggi altre domande sui tag