Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I keep getting to test this kind of code (language irrelevant) :

public class Foo() {

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

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

Typically, you want to test what when the dependency fires the event, the class under tests reacts appropriately (in some situation, the only purpose of such classes is to wire lots of other components, that can be independently tested.

So far, to test this, I always end up doing something like :

  • creating a 'stub' that implements both a addXXXXListener, that simply stores the callback, and a fireXXXX, that simply calls any registered listener. This is a bit tedious since you have to create the mock with the right interface, but that can do
  • use an introspective framework that can 'spy' on a method, and inject the real dependency in tests

Is there a cleaner way to do this kind of things ?

EDIT : to clarify what I mean, my trouble is that if I could write something like this :

public class FooTest() {

  public void testListensToDependencies() {

   IDependency mockDependency = createMock(IDependency.class)

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

   expect(mockDependency.addSomeEventListener).toHaveBeenCalled();

  }
}

However, obviously this test would pass no matter what the listener does. This is troubling me, since I want to test that I am wiring my objects to do the proper thing.

The next best thing would be :

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

And then I would write tests to :

  • check that the 'addSomeEventListener' was called either with the right handler function, or with an instance of the right event handler class

  • check that the handler function, or the event handler class, actually implement the expected behavior.

Now I am not sure if that would be clearer, or if it is the sign I'm wiring my objects at the wrong place....

share|improve this question
add comment

migrated from stackoverflow.com Oct 24 '12 at 2:20

This question came from our site for professional and enthusiast programmers.

1 Answer

When you are unit testing class Foo, you should only go so far as to check that

a) add listener is called on your mock and b) the event is fired on the mock

After all, when you are unit testing class foo, you shouldn't care what your dependant class (Dependency1 in your example) is doing internally. Otherwise you are testing more than the unit Foo. Mocking frameworks, for example, Moq will typically provide you with a way to assert that a given method is called on your mock, you can even assert the number of times that you expect the method to be called.

here is rough example using Moq in C# (haven't compiled this it's just to give an 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());

It is your unit testing of Dependency1 that should verify it's internal behaviour.

share|improve this answer
    
Just to clarify : in my case, it is the dependency that raises the event. The SUT's job is to react to this event in a specific way. –  phtrivier Oct 24 '12 at 15:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.