Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Manning.The.Art.of.Unit.Testing.with.Examples.in.dot.NET.Jun.2009.pdf
Скачиваний:
18
Добавлен:
21.03.2016
Размер:
9.67 Mб
Скачать

Testing for event-related activities

121

...

using (mocks.Record())

{

mockservice.LogError(new TraceMessage("", 0, "")); LastCall.Constraints(

Is.Matching<ComplexTraceMessage>(verifyComplexMessage));

}

...

}

private bool verifyComplexMessage(ComplexTraceMessage msg)

{

if (msg.InnerMessage.Severity < 50

&& msg.InnerMessage.Message.Contains("a"))

{

return false;

}

return true;

}

Rhino Mocks has a simpler syntax if you’re only testing a method that accepts a single parameter. Instead of using this syntax,

LastCall.Constraints(

Is.Matching<ComplexTraceMessage>(verifyComplexMessage));

you can write this:

LastCall.Callback(verifyComplexMessage);

Next, we’ll see how to test whether objects raise events properly, or whether other objects have registered for an event properly.

5.7 Testing for event-related activities

Testing event-related actions has always been one of the gaping holes in isolation frameworks and has required manual workarounds to test things such as whether an object registered to get an event from another object, or whether an object triggered an event when it should have. Rhino Mocks has facilities to help in these areas as well.

The first scenario we’ll tackle is checking whether an object registered to receive an event from another object.

122

CHAPTER 5

Isolation (mock object) frameworks

5.7.1Testing that an event has been subscribed to

Let’s assume we have a Presenter class that needs to register to the Load event of a view class it receives. The code for presenter might look like listing 5.17.

Listing 5.17 Testing that an event was registered properly

public class Presenter

{

IView view;

public Presenter(IView view)

{

this.view = view;

this.view.Load += new EventHandler(view_Load);

}

void view_Load(object sender, EventArgs e)

{

throw new Exception("Not implemented.");

}

}

?

Registers for real event

[Test]

public void VerifyAttachesToViewEvents()

{

MockRepository mocks = new MockRepository();

IView viewMock = (IView)mocks.CreateMock(typeof(IView)); using (mocks.Record())

{

 

 

viewMock.Load += null;

 

w Records expected

 

LastCall.IgnoreArguments();

event registration

}

 

 

new Presenter(viewMock);

 

mocks.VerifyAll();

 

}

During the recording stage, we overload the Load event ?. Then we make sure we ignore the arguments in the call, and make sure the call happened w.

Some people find that testing whether an event was subscribed to is helpful, but knowing that someone has registered to an event doesn’t

Testing for event-related activities

123

mean she did something meaningful with it. It’s not a real functional requirement that’s tested here. If I were doing a test review, I’d say that this was not needed. Instead, you should test that something happened in response to the event being triggered.

To test this scenario as part of a functional requirement, we could say that, upon getting the Load event, the presenter’s production code will do something that we can see from our test (write to a log, for example). To get that something to happen, we need to find a way to trigger the event from within the stub object and see if the presenter does that action in response. That’s what the next section is about.

5.7.2Triggering events from mocks and stubs

Listing 5.18 shows a test that makes sure Presenter writes to a log upon getting an event from our stub. It also uses a class called EventRaiser, which triggers the event from the interface.

Listing 5.18 Triggering an event via the EventRaiser class in Rhino Mocks

[Test]

 

 

 

 

public void TriggerAndVerifyRespondingToEvents()

 

 

 

 

{

 

 

 

 

 

 

 

Uses stub

 

 

MockRepository mocks = new MockRepository();

 

 

 

? for event

IView viewStub = mocks.Stub<IView>();

 

 

 

triggering

 

 

 

 

IWebService serviceMock =

 

 

 

 

mocks.CreateMock<IWebService>();

 

 

 

w Uses mock to

 

 

 

using (mocks.Record())

 

 

 

check log call

{

 

 

 

 

 

 

 

 

serviceMock.LogInfo("view loaded");

 

 

 

 

}

 

 

 

 

 

 

 

 

new Presenter(viewStub,serviceMock);

 

Creates

 

 

 

 

 

 

event

IEventRaiser eventer =

 

raiser

 

 

 

 

EventRaiser.Create(viewStub, "Load");

 

 

 

 

Triggers event

eventer.Raise(null,EventArgs.Empty);

 

 

 

mocks.Verify(serviceMock);

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

124

CHAPTER 5

Isolation (mock object) frameworks

Another way of getting an EventRaiser object is by using the recording mechanism:

IEventRaiser eventer; using (mocks.Record())

{

viewStub.Load += null;

eventer = LastCall.GetEventRaiser();

}

Notice in listing 5.18 that we’re using a stub ?to trigger the event, and a mock w to check that the service was written to. The EventRaiser takes a stub or a mock and the name of the event to raise from that stub

or mock. The Raise() method of EventRaiser takes a params object[]

array that requires you to send the number of parameters that the event signature requires. The verification of whether the message was received happened against the mock service.

Now, let’s take a look at the opposite end of the testing scenario. Instead of testing the subscriber, we’d like to make sure that the event source triggers the event at the right time. The next section shows how we can do that.

5.7.3Testing whether an event was triggered

There are two basic approaches to testing that an event was triggered. One is simple, but only works in C#, and the other takes a bit more work, but will work in VB.NET. First, let’s look at the simplest way—using a handwritten anonymous method.

Testing event firing inline

A simple way to test the event is by manually registering to it inside the test method using an anonymous delegate. Listing 5.19 shows a simple example.

Listing 5.19 Using an anonymous delegate to register to an event

[Test]

public void EventFiringManual()

{

bool loadFired = false;

Testing for event-related activities

125

SomeView view = new SomeView(); view.Load+=delegate

{

loadFired = true;

};

view.TriggerLoad(null, EventArgs.Empty); Assert.IsTrue(loadFired);

}

The delegate simply records whether the event was fired or not. You could also have it record the values, and they could later be asserted as well. That code could become quite cumbersome, but most of the time it’s quite a workable solution, and I recommend it if you use C#. Unfortunately, this won’t work in VB.NET because VB.NET currently doesn’t support inline anonymous delegates that don’t return a value. (It does support nonvoid anonymous delegates and will support the void ones in version 10.)

With VB.NET, the solution requires a bit more work. You need to send in the address of a full method in the class, and have that method set a class scope variable flag telling our test whether the event was fired or not. It’s not as clean as I’d like, but it works.

The next section shows a less cumbersome way to test the event triggering and the values that are passed in if we can’t use anonymous delegates.

Using EventsVerifier for event testing

Another approach is to use a class called EventsVerifier (not part of Rhino Mocks), which will dynamically register against the required delegate and verify the values that are passed in by the fired event. EventsVerifier can be downloaded from http://weblogs.asp.net/ rosherove/archive/2005/06/13/EventsVerifier.aspx. Listing 5.20 shows an example of its use.

Listing 5.20 Using the EventsVerifier class to test for event values

[Test]

public void EventFiringWithEventsVerifier()

{

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]