1

I have a code which looks like example below:

public interface IDependency
{
    void Foo();
}


public class MainClass{

    Timer tmr = new Timer(100);
    IDependency dependency;

    public MainClass(IDependency dep)
    {
        dependency = dep;
        tmr.Elapsed += OnElapsed;
    }

    void OnElapsed(object sender, EventArgs e)
    {
        dependency.Foo();
    }

    public void Start()=> tmr.Start();
    public void Stop() => tmr.Stop();

}

Using RhinoMock and/or nunit, I want to unit-test that once 'Stop' is called, IDependency.Foo is no longer being called

Tried using BackToRecord and ReplayAll, but could not achieve the goal. Calling AssertWasNotCalled does not fail after calling Stop().

Is there any way to achieve the same?

Amittai Shapira
  • 3,749
  • 1
  • 30
  • 54
Pramod B R
  • 612
  • 6
  • 7

2 Answers2

1

Since the interval of the timer is known you can wait a set time and count how many times the timer invoked Foo.

For example

[TestMethod]
public async Task MainClass_Should_Stop() {
    //Arrange
    var dependency = Substitute.For<IDependency>();
    var subject = new MainClass(dependency);
    var expectedDelay = 200;
    var expectedCalls = 2;

    //Act
    subject.Start();
    await Task.Delay(expectedDelay);
    subject.Stop();
    await Task.Delay(100);

    //Assert
    dependency.Received(expectedCalls).Foo();
}

While the above uses NSubstitute, the same can be applied with your mocking framework of choice.

If I were to change the expected delay to one that would cause the expected calls to differ then the test would fail.

For example when the delay is set to 100ms and the calls remain at 2 then it would fail because only one call would have happened.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • While this looks OK (have not tried yet), I would like a method which does not depend on the timer elapsed time. What I am looking is whether we can 'clear' the recordings of the mock once the Stop is called and then ensure the method is not getting called. – Pramod B R Jun 28 '19 at 10:08
  • @PramodBR - how would you know the method is not getting called without waiting? I'd assume a test should wait at least for the timer period (and probably timer period + epsilon), to verify there was actually no call... – Amittai Shapira Jul 23 '19 at 15:01
  • @Amittai Shapira I agree the test should wait. But I would like to avoid depending on the interval of the timer. Rather I would like to check if the method is NOT called after the Stop method is called without depending on the internal implementation details. – Pramod B R Jul 24 '19 at 14:54
  • @PramodBR - I'm not sure how would you do that... let's assume the interval is 5 minutes, and you call Start() and then Stop() without waiting. In such test asserting that the method wasn't called doesn't verify that Stop() worked, as the method may be called after the test is completed... – Amittai Shapira Jul 24 '19 at 15:02
1

Following Nkosi answer, here's how you'd do it with Rhino Mocks (see also some discussion in this question):

[Test]
public async Task MainClass_Should_Stop() {
    //Arrange
    var dependency = MockRepository.GenerateMock<IDependency>();
    var subject = new MainClass(dependency);
    var expectedDelay = 200;
    var expectedCalls = 2;

    //Act
    subject.Start();
    await Task.Delay(expectedDelay);
    subject.Stop();
    await Task.Delay(100);

    //Assert
    dependency.AssertWasCalled(
      dependency => dependency.Foo(),
      options => options.Repeat.Times(expectedCalls)
  );
}
Amittai Shapira
  • 3,749
  • 1
  • 30
  • 54