I am writing a client which sends a "heartbeat signal" to the server every second. The client calls a WCF service in the background thread to report its activity.
How to unit test this? Do I need to wait for a couple of seconds and check if appropriate method was called several times?
Should it be some sort of scenario test instead? Maybe I shouldn't be worried about calling the service continuously through the whole clients lifetime cycle?
I can test a single call to WCF service but it doesn't test the "heartbeat pattern".
I am using TDD approach. (C#, NUnit, Moq)
Any suggestions or examples?
EDIT:
I think it wasn't clear enough.
This is a much simpler version of what I have:
public class FeedService
{
private Timer t;
public FeedService()
{
t.Interval = 1000;
t.Elapsed += TimerElapsed;
t.Start();
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
t.Stop();
SendHeartbeat();
t.Start();
}
}
...and this is my test:
[Test]
public void Heartbeat_called_twice_after_2_seconds()
{
var mockFeedService = new Mock<FeedService>();
Thread.Sleep(200开发者_如何学编程0);
mockFeedService.Verify(x => x.SendHeartBeat(), Times.AtLeast(2));
}
I have a two questions:
1) Why my test always fails? What I am doing wrong? 2) Should I test it at all?The functionality that you wish to test must be first isolated. For example in this case, there are a two aspects that could be tested. One is that the hearbeat component actually sends a heartbeat message on the designated schedule. The other is that the service receives the message. If you abstract the service, then you can test the hearbeat component in isolation from the service implementation. This can be done in a unit test by starting the hearbeat component, then sleeping, then verifying that the expected number of messages were received by the stub or mock service implementation. The test that ensures the service is receiving the message is an integration test and so is a not a "pure" unit test. However, since it must be tested anyway, you can have a test case for this as well.
I would wrap the interaction with the service in a "gateway" type class. This can be replaced by a mock in your test, and the mock can count the calls that you make, or whatever statistics you might need.
Regards, Morten
The scenario you want to test is, strictly speaking, an integration test.
The approach I've taken to similar test-construction scenarios is to use this handy function:
/// <summary>
/// Wait no longer than @waitNoLongerThanMillis for @thatWhatWeAreWaitingFor to return true.
/// Tests every second for the
/// </summary>
/// <param name="thatWhatWeAreWaitingFor">Function that when evaluated returns true if the state we are waiting for has been reached.</param>
/// <param name="waitNoLongerThanMillis">Max time to wait in milliseconds</param>
/// <param name="checkEveryMillis">How often to check for @thatWhatWeAreWaitingFor</param>
/// <returns></returns>
private bool WaitFor(Func<bool> thatWhatWeAreWaitingFor, int checkEveryMillis, int waitNoLongerThanMillis)
{
var waitedFor = 0;
while (waitedFor < waitNoLongerThanMillis)
{
if (thatWhatWeAreWaitingFor()) return true;
Console.WriteLine("Waiting another {0}ms for a situation to occur. Giving up in {1}ms ...", checkEveryMillis, (waitNoLongerThanMillis - waitedFor));
Thread.Sleep(checkEveryMillis);
waitedFor += checkEveryMillis;
}
return false;
}
Usage:
// WaitFor (transaction to become failed, checkEverySoOften, waitNoLongerThan)
int wait = (Settings.EventHandlerCoordinatorNoActivitySleepTime + 5) * 1000;
var failedEventExists = WaitFor(() => EventQueueManager.GetFailedEvents(0, 10).TotalRecords > 0, checkEveryMillis: 1000, waitNoLongerThanMillis: wait);
if (!failedEventExists)
Assert.Fail("Waited longer than " + wait + " without any evidence of the event having been handled. Expected to failed event on the queue.");
It uses c# features only available since .Net4 but that probably suits most .Net developers these days.
精彩评论