Unit Test heartbeat functionality
I have a client-server system based on TCP coded in C#. I was requested to add a bidirectional heartbeat to discover if any of the elements in the network freeze and are not responding.
I solved the problem by sending a heartbeat from the server to all connected clients and waiting for the response. There's a timeout if the response doesn't come on time and there is a timeout in the clients if the server didn't send any heartbeat in 2 seconds (assuming the server is frozen).
Everything happens internally and the server nor the client expose any of the events (receiving a heartbeat, replying a heartbeat happen silently, as it was requested)
The thing is .. How does one create a unit test or integration test for such a functionality?
Note: I'm coding in visual studio, C#, .Net 4.6.1, testing using NUnit3
Brief pseudocode example:
//we have one connector for each connected client
class connector{
//if the echoReceived timer is not reseted on time it will complain
Timer echoReceived = new Timer(200ms);
//Another timer for sending beats
Timer heartbeatSender = new Timer (1000ms);
OnClientConnected(Client)
{
echoReceived.elapsed += () => { ShowError("Client did not reply") };
heartbeatSender.elapsed += () => {
Send(client, new Message(Heartbeat));
echoReceived.Enabled = true;
});
heartbeatSemder.isEnabled = true;
}
OnNewMessageFromClient(Client, message)
{
if(message is echoedHeartBeat)
{
echoReceived.Enabled= false;
echoReceived.Reset();
}
}
}
On the client side
class client
{
Timer ServerDeadTimeOut = new Timer (1000ms);
OnStart()
{
serverDeadTimeOut.Elapsed += () => { ShowError("Server is dead"); };
serverDeadTimeOut.isEnabled = true;
}
OnNewMessageFromServer(message)
{
if(message is HeartBeatMessage)
{
serverDeadTimeOut.Reset();
Send(new HeartBeatEchoMessage);
}
}
}
c# unit-testing nunit client-server integration-testing
add a comment |
I have a client-server system based on TCP coded in C#. I was requested to add a bidirectional heartbeat to discover if any of the elements in the network freeze and are not responding.
I solved the problem by sending a heartbeat from the server to all connected clients and waiting for the response. There's a timeout if the response doesn't come on time and there is a timeout in the clients if the server didn't send any heartbeat in 2 seconds (assuming the server is frozen).
Everything happens internally and the server nor the client expose any of the events (receiving a heartbeat, replying a heartbeat happen silently, as it was requested)
The thing is .. How does one create a unit test or integration test for such a functionality?
Note: I'm coding in visual studio, C#, .Net 4.6.1, testing using NUnit3
Brief pseudocode example:
//we have one connector for each connected client
class connector{
//if the echoReceived timer is not reseted on time it will complain
Timer echoReceived = new Timer(200ms);
//Another timer for sending beats
Timer heartbeatSender = new Timer (1000ms);
OnClientConnected(Client)
{
echoReceived.elapsed += () => { ShowError("Client did not reply") };
heartbeatSender.elapsed += () => {
Send(client, new Message(Heartbeat));
echoReceived.Enabled = true;
});
heartbeatSemder.isEnabled = true;
}
OnNewMessageFromClient(Client, message)
{
if(message is echoedHeartBeat)
{
echoReceived.Enabled= false;
echoReceived.Reset();
}
}
}
On the client side
class client
{
Timer ServerDeadTimeOut = new Timer (1000ms);
OnStart()
{
serverDeadTimeOut.Elapsed += () => { ShowError("Server is dead"); };
serverDeadTimeOut.isEnabled = true;
}
OnNewMessageFromServer(message)
{
if(message is HeartBeatMessage)
{
serverDeadTimeOut.Reset();
Send(new HeartBeatEchoMessage);
}
}
}
c# unit-testing nunit client-server integration-testing
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26
add a comment |
I have a client-server system based on TCP coded in C#. I was requested to add a bidirectional heartbeat to discover if any of the elements in the network freeze and are not responding.
I solved the problem by sending a heartbeat from the server to all connected clients and waiting for the response. There's a timeout if the response doesn't come on time and there is a timeout in the clients if the server didn't send any heartbeat in 2 seconds (assuming the server is frozen).
Everything happens internally and the server nor the client expose any of the events (receiving a heartbeat, replying a heartbeat happen silently, as it was requested)
The thing is .. How does one create a unit test or integration test for such a functionality?
Note: I'm coding in visual studio, C#, .Net 4.6.1, testing using NUnit3
Brief pseudocode example:
//we have one connector for each connected client
class connector{
//if the echoReceived timer is not reseted on time it will complain
Timer echoReceived = new Timer(200ms);
//Another timer for sending beats
Timer heartbeatSender = new Timer (1000ms);
OnClientConnected(Client)
{
echoReceived.elapsed += () => { ShowError("Client did not reply") };
heartbeatSender.elapsed += () => {
Send(client, new Message(Heartbeat));
echoReceived.Enabled = true;
});
heartbeatSemder.isEnabled = true;
}
OnNewMessageFromClient(Client, message)
{
if(message is echoedHeartBeat)
{
echoReceived.Enabled= false;
echoReceived.Reset();
}
}
}
On the client side
class client
{
Timer ServerDeadTimeOut = new Timer (1000ms);
OnStart()
{
serverDeadTimeOut.Elapsed += () => { ShowError("Server is dead"); };
serverDeadTimeOut.isEnabled = true;
}
OnNewMessageFromServer(message)
{
if(message is HeartBeatMessage)
{
serverDeadTimeOut.Reset();
Send(new HeartBeatEchoMessage);
}
}
}
c# unit-testing nunit client-server integration-testing
I have a client-server system based on TCP coded in C#. I was requested to add a bidirectional heartbeat to discover if any of the elements in the network freeze and are not responding.
I solved the problem by sending a heartbeat from the server to all connected clients and waiting for the response. There's a timeout if the response doesn't come on time and there is a timeout in the clients if the server didn't send any heartbeat in 2 seconds (assuming the server is frozen).
Everything happens internally and the server nor the client expose any of the events (receiving a heartbeat, replying a heartbeat happen silently, as it was requested)
The thing is .. How does one create a unit test or integration test for such a functionality?
Note: I'm coding in visual studio, C#, .Net 4.6.1, testing using NUnit3
Brief pseudocode example:
//we have one connector for each connected client
class connector{
//if the echoReceived timer is not reseted on time it will complain
Timer echoReceived = new Timer(200ms);
//Another timer for sending beats
Timer heartbeatSender = new Timer (1000ms);
OnClientConnected(Client)
{
echoReceived.elapsed += () => { ShowError("Client did not reply") };
heartbeatSender.elapsed += () => {
Send(client, new Message(Heartbeat));
echoReceived.Enabled = true;
});
heartbeatSemder.isEnabled = true;
}
OnNewMessageFromClient(Client, message)
{
if(message is echoedHeartBeat)
{
echoReceived.Enabled= false;
echoReceived.Reset();
}
}
}
On the client side
class client
{
Timer ServerDeadTimeOut = new Timer (1000ms);
OnStart()
{
serverDeadTimeOut.Elapsed += () => { ShowError("Server is dead"); };
serverDeadTimeOut.isEnabled = true;
}
OnNewMessageFromServer(message)
{
if(message is HeartBeatMessage)
{
serverDeadTimeOut.Reset();
Send(new HeartBeatEchoMessage);
}
}
}
c# unit-testing nunit client-server integration-testing
c# unit-testing nunit client-server integration-testing
edited Nov 27 '18 at 16:00
W.Ambrozic
901212
901212
asked Nov 16 '18 at 8:29
javirsjavirs
562734
562734
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26
add a comment |
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26
add a comment |
2 Answers
2
active
oldest
votes
I'd go for Unit Tests, integration would require setting up some kind of connection between these two, depending on implementation it can be easier or harder. Unit Tests would simply rely on the abstraction. Just inject interfaces to the Connector and for unit testing replace them with Mocks to simulate scenarios that you designed that class for. Of course then you have to test actual implementations of Timer, Logger and ClientListener, but that's what unit tests are for.
public class ConnectorTest
{
private readonly Connector _connector;
private readonly TimerMock _receiverMock;
private readonly TimerMock _senderMock;
private readonly LoggerMock _loggerMock;
private readonly ClientListenerMock _listenerMock;
public void Setup()
{
_listenerMock = new ClientListenerMock();
_receiverMock = new TimerMock();
_senderMock = new TimerMock();
_loggerMock = new LoggerMock();
_connector = new Connector(_listenerMock, _receiverMock, _senderMock, _loggerMock)
}
public void HeartbeatSender_ShouldBeEnabled_OnceClientIsConnected()
{
_listenerMock.SimulateClientConnection();
Assert.IsTrue(_senderMock.IsEnabled);
}
public void Error_ShouldBeLogged_WhenConnectedClientDidNotEchoed()
{
_listenerMock.SimulateClientConnection();
_receiverMock.SimulateEchoTimeout();
Assert.AreEqual("Client did not reply", _loggerMock.RecentErrorMessage);
}
}
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test thatheartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.
– javirs
Nov 23 '18 at 8:24
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
add a comment |
I think unit testing this class would be fairly simple if we just make a couple of small changes. First of all you'd surely like to get rid of the following:
Timer echoReceived = new Timer(200ms);
Waiting 200ms in a each unit test doesn't sound like a good idea. What you could do instead, is to extract this 200 ms into a class field initialized from the constructor so that you can pass it lower values, such as 1ms. But actually, you could make it even better by defining an interface like ITimer that could look something like:
interface ITimer
{
int Interval { get; }
event EventHandler OnElapsed;
void Reset();
}
This way, in the unit test you could provide a stub e.g. implemented like this
class StubTimer
{
[...]
void TickNow()
{
OnElapsed.Invoke( ... ) // fire the event, to avoid Thread.Sleep (waiting n miliseconds)
}
[...]
}
You probabbly should also take ShowError
function as constructor parameter, assigning it to property of type like Action<ErrorArgs>
.Then, you can just unit test it like so:
public void WhenClientConnected_ButThereIsNoResponse_ItShouldCallShowError()
{
var stubHearbeatTimer = new StubTimer();
var stubTimeoutTimer = new StubTimer();
// i'm pretty sure it's possibile mock Actions with moq as well
var wasSendErrorCalled = false;
var stubErrorAction = (args) => {
wasSendErrorCalled = true;
};
var sut = new connector(stubHearbeatTimer, stubTimeoutTimer, stubErrorAction );
sut.OnClientConnected( ..dummyClient..);
stubTimeoutTimer.TickNow();
Assert.IsTrue(wasSendErrorCalled);
}
Please note it's just a pseudecode though. Hope this answers your question!
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53334035%2funit-test-heartbeat-functionality%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'd go for Unit Tests, integration would require setting up some kind of connection between these two, depending on implementation it can be easier or harder. Unit Tests would simply rely on the abstraction. Just inject interfaces to the Connector and for unit testing replace them with Mocks to simulate scenarios that you designed that class for. Of course then you have to test actual implementations of Timer, Logger and ClientListener, but that's what unit tests are for.
public class ConnectorTest
{
private readonly Connector _connector;
private readonly TimerMock _receiverMock;
private readonly TimerMock _senderMock;
private readonly LoggerMock _loggerMock;
private readonly ClientListenerMock _listenerMock;
public void Setup()
{
_listenerMock = new ClientListenerMock();
_receiverMock = new TimerMock();
_senderMock = new TimerMock();
_loggerMock = new LoggerMock();
_connector = new Connector(_listenerMock, _receiverMock, _senderMock, _loggerMock)
}
public void HeartbeatSender_ShouldBeEnabled_OnceClientIsConnected()
{
_listenerMock.SimulateClientConnection();
Assert.IsTrue(_senderMock.IsEnabled);
}
public void Error_ShouldBeLogged_WhenConnectedClientDidNotEchoed()
{
_listenerMock.SimulateClientConnection();
_receiverMock.SimulateEchoTimeout();
Assert.AreEqual("Client did not reply", _loggerMock.RecentErrorMessage);
}
}
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test thatheartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.
– javirs
Nov 23 '18 at 8:24
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
add a comment |
I'd go for Unit Tests, integration would require setting up some kind of connection between these two, depending on implementation it can be easier or harder. Unit Tests would simply rely on the abstraction. Just inject interfaces to the Connector and for unit testing replace them with Mocks to simulate scenarios that you designed that class for. Of course then you have to test actual implementations of Timer, Logger and ClientListener, but that's what unit tests are for.
public class ConnectorTest
{
private readonly Connector _connector;
private readonly TimerMock _receiverMock;
private readonly TimerMock _senderMock;
private readonly LoggerMock _loggerMock;
private readonly ClientListenerMock _listenerMock;
public void Setup()
{
_listenerMock = new ClientListenerMock();
_receiverMock = new TimerMock();
_senderMock = new TimerMock();
_loggerMock = new LoggerMock();
_connector = new Connector(_listenerMock, _receiverMock, _senderMock, _loggerMock)
}
public void HeartbeatSender_ShouldBeEnabled_OnceClientIsConnected()
{
_listenerMock.SimulateClientConnection();
Assert.IsTrue(_senderMock.IsEnabled);
}
public void Error_ShouldBeLogged_WhenConnectedClientDidNotEchoed()
{
_listenerMock.SimulateClientConnection();
_receiverMock.SimulateEchoTimeout();
Assert.AreEqual("Client did not reply", _loggerMock.RecentErrorMessage);
}
}
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test thatheartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.
– javirs
Nov 23 '18 at 8:24
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
add a comment |
I'd go for Unit Tests, integration would require setting up some kind of connection between these two, depending on implementation it can be easier or harder. Unit Tests would simply rely on the abstraction. Just inject interfaces to the Connector and for unit testing replace them with Mocks to simulate scenarios that you designed that class for. Of course then you have to test actual implementations of Timer, Logger and ClientListener, but that's what unit tests are for.
public class ConnectorTest
{
private readonly Connector _connector;
private readonly TimerMock _receiverMock;
private readonly TimerMock _senderMock;
private readonly LoggerMock _loggerMock;
private readonly ClientListenerMock _listenerMock;
public void Setup()
{
_listenerMock = new ClientListenerMock();
_receiverMock = new TimerMock();
_senderMock = new TimerMock();
_loggerMock = new LoggerMock();
_connector = new Connector(_listenerMock, _receiverMock, _senderMock, _loggerMock)
}
public void HeartbeatSender_ShouldBeEnabled_OnceClientIsConnected()
{
_listenerMock.SimulateClientConnection();
Assert.IsTrue(_senderMock.IsEnabled);
}
public void Error_ShouldBeLogged_WhenConnectedClientDidNotEchoed()
{
_listenerMock.SimulateClientConnection();
_receiverMock.SimulateEchoTimeout();
Assert.AreEqual("Client did not reply", _loggerMock.RecentErrorMessage);
}
}
I'd go for Unit Tests, integration would require setting up some kind of connection between these two, depending on implementation it can be easier or harder. Unit Tests would simply rely on the abstraction. Just inject interfaces to the Connector and for unit testing replace them with Mocks to simulate scenarios that you designed that class for. Of course then you have to test actual implementations of Timer, Logger and ClientListener, but that's what unit tests are for.
public class ConnectorTest
{
private readonly Connector _connector;
private readonly TimerMock _receiverMock;
private readonly TimerMock _senderMock;
private readonly LoggerMock _loggerMock;
private readonly ClientListenerMock _listenerMock;
public void Setup()
{
_listenerMock = new ClientListenerMock();
_receiverMock = new TimerMock();
_senderMock = new TimerMock();
_loggerMock = new LoggerMock();
_connector = new Connector(_listenerMock, _receiverMock, _senderMock, _loggerMock)
}
public void HeartbeatSender_ShouldBeEnabled_OnceClientIsConnected()
{
_listenerMock.SimulateClientConnection();
Assert.IsTrue(_senderMock.IsEnabled);
}
public void Error_ShouldBeLogged_WhenConnectedClientDidNotEchoed()
{
_listenerMock.SimulateClientConnection();
_receiverMock.SimulateEchoTimeout();
Assert.AreEqual("Client did not reply", _loggerMock.RecentErrorMessage);
}
}
answered Nov 22 '18 at 21:45
yogeryoger
312210
312210
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test thatheartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.
– javirs
Nov 23 '18 at 8:24
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
add a comment |
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test thatheartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.
– javirs
Nov 23 '18 at 8:24
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test that
heartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.– javirs
Nov 23 '18 at 8:24
I think I dont get your solution. You wrote like 50 lines of code (with potential bug's) to test that
heartbeatSemder.isEnabled = true;
happened. But you don't care about heartbeat pulses actually being sent or not. Just that this line was called. As for the second one.. I don't know how you simulate a timeout but I fear you just call an event so .. .the heartbeat system is not tested at all.– javirs
Nov 23 '18 at 8:24
2
2
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
It's more or less just to supplement the description I made. I didn't create full test solution for your pseudocode. Just provided an idea of how to unit test it.
– yoger
Nov 23 '18 at 9:18
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
but the question is how to unit test that the timers ar correct, that the autoresets are ok, and that the whole heartbeat solution works
– javirs
Nov 23 '18 at 9:19
2
2
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
unit testing timers are not easy because you they are asynchronous by design, so approch with unit testing is very good idea (abstracting real network connection and everything which could change the result of a test breaking repeatable unit test rule). use some mocking library like moq, refactor classes to relay on abstractions (interfaces), then mock timers or other components not related to logic u want to test.
– Macko
Nov 24 '18 at 20:48
add a comment |
I think unit testing this class would be fairly simple if we just make a couple of small changes. First of all you'd surely like to get rid of the following:
Timer echoReceived = new Timer(200ms);
Waiting 200ms in a each unit test doesn't sound like a good idea. What you could do instead, is to extract this 200 ms into a class field initialized from the constructor so that you can pass it lower values, such as 1ms. But actually, you could make it even better by defining an interface like ITimer that could look something like:
interface ITimer
{
int Interval { get; }
event EventHandler OnElapsed;
void Reset();
}
This way, in the unit test you could provide a stub e.g. implemented like this
class StubTimer
{
[...]
void TickNow()
{
OnElapsed.Invoke( ... ) // fire the event, to avoid Thread.Sleep (waiting n miliseconds)
}
[...]
}
You probabbly should also take ShowError
function as constructor parameter, assigning it to property of type like Action<ErrorArgs>
.Then, you can just unit test it like so:
public void WhenClientConnected_ButThereIsNoResponse_ItShouldCallShowError()
{
var stubHearbeatTimer = new StubTimer();
var stubTimeoutTimer = new StubTimer();
// i'm pretty sure it's possibile mock Actions with moq as well
var wasSendErrorCalled = false;
var stubErrorAction = (args) => {
wasSendErrorCalled = true;
};
var sut = new connector(stubHearbeatTimer, stubTimeoutTimer, stubErrorAction );
sut.OnClientConnected( ..dummyClient..);
stubTimeoutTimer.TickNow();
Assert.IsTrue(wasSendErrorCalled);
}
Please note it's just a pseudecode though. Hope this answers your question!
add a comment |
I think unit testing this class would be fairly simple if we just make a couple of small changes. First of all you'd surely like to get rid of the following:
Timer echoReceived = new Timer(200ms);
Waiting 200ms in a each unit test doesn't sound like a good idea. What you could do instead, is to extract this 200 ms into a class field initialized from the constructor so that you can pass it lower values, such as 1ms. But actually, you could make it even better by defining an interface like ITimer that could look something like:
interface ITimer
{
int Interval { get; }
event EventHandler OnElapsed;
void Reset();
}
This way, in the unit test you could provide a stub e.g. implemented like this
class StubTimer
{
[...]
void TickNow()
{
OnElapsed.Invoke( ... ) // fire the event, to avoid Thread.Sleep (waiting n miliseconds)
}
[...]
}
You probabbly should also take ShowError
function as constructor parameter, assigning it to property of type like Action<ErrorArgs>
.Then, you can just unit test it like so:
public void WhenClientConnected_ButThereIsNoResponse_ItShouldCallShowError()
{
var stubHearbeatTimer = new StubTimer();
var stubTimeoutTimer = new StubTimer();
// i'm pretty sure it's possibile mock Actions with moq as well
var wasSendErrorCalled = false;
var stubErrorAction = (args) => {
wasSendErrorCalled = true;
};
var sut = new connector(stubHearbeatTimer, stubTimeoutTimer, stubErrorAction );
sut.OnClientConnected( ..dummyClient..);
stubTimeoutTimer.TickNow();
Assert.IsTrue(wasSendErrorCalled);
}
Please note it's just a pseudecode though. Hope this answers your question!
add a comment |
I think unit testing this class would be fairly simple if we just make a couple of small changes. First of all you'd surely like to get rid of the following:
Timer echoReceived = new Timer(200ms);
Waiting 200ms in a each unit test doesn't sound like a good idea. What you could do instead, is to extract this 200 ms into a class field initialized from the constructor so that you can pass it lower values, such as 1ms. But actually, you could make it even better by defining an interface like ITimer that could look something like:
interface ITimer
{
int Interval { get; }
event EventHandler OnElapsed;
void Reset();
}
This way, in the unit test you could provide a stub e.g. implemented like this
class StubTimer
{
[...]
void TickNow()
{
OnElapsed.Invoke( ... ) // fire the event, to avoid Thread.Sleep (waiting n miliseconds)
}
[...]
}
You probabbly should also take ShowError
function as constructor parameter, assigning it to property of type like Action<ErrorArgs>
.Then, you can just unit test it like so:
public void WhenClientConnected_ButThereIsNoResponse_ItShouldCallShowError()
{
var stubHearbeatTimer = new StubTimer();
var stubTimeoutTimer = new StubTimer();
// i'm pretty sure it's possibile mock Actions with moq as well
var wasSendErrorCalled = false;
var stubErrorAction = (args) => {
wasSendErrorCalled = true;
};
var sut = new connector(stubHearbeatTimer, stubTimeoutTimer, stubErrorAction );
sut.OnClientConnected( ..dummyClient..);
stubTimeoutTimer.TickNow();
Assert.IsTrue(wasSendErrorCalled);
}
Please note it's just a pseudecode though. Hope this answers your question!
I think unit testing this class would be fairly simple if we just make a couple of small changes. First of all you'd surely like to get rid of the following:
Timer echoReceived = new Timer(200ms);
Waiting 200ms in a each unit test doesn't sound like a good idea. What you could do instead, is to extract this 200 ms into a class field initialized from the constructor so that you can pass it lower values, such as 1ms. But actually, you could make it even better by defining an interface like ITimer that could look something like:
interface ITimer
{
int Interval { get; }
event EventHandler OnElapsed;
void Reset();
}
This way, in the unit test you could provide a stub e.g. implemented like this
class StubTimer
{
[...]
void TickNow()
{
OnElapsed.Invoke( ... ) // fire the event, to avoid Thread.Sleep (waiting n miliseconds)
}
[...]
}
You probabbly should also take ShowError
function as constructor parameter, assigning it to property of type like Action<ErrorArgs>
.Then, you can just unit test it like so:
public void WhenClientConnected_ButThereIsNoResponse_ItShouldCallShowError()
{
var stubHearbeatTimer = new StubTimer();
var stubTimeoutTimer = new StubTimer();
// i'm pretty sure it's possibile mock Actions with moq as well
var wasSendErrorCalled = false;
var stubErrorAction = (args) => {
wasSendErrorCalled = true;
};
var sut = new connector(stubHearbeatTimer, stubTimeoutTimer, stubErrorAction );
sut.OnClientConnected( ..dummyClient..);
stubTimeoutTimer.TickNow();
Assert.IsTrue(wasSendErrorCalled);
}
Please note it's just a pseudecode though. Hope this answers your question!
answered Nov 27 '18 at 22:20
Mateusz UrbanMateusz Urban
16816
16816
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53334035%2funit-test-heartbeat-functionality%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
abstract out implementation concerns that would allow more flexibility testing expected behavior.
– Nkosi
Nov 27 '18 at 16:26