1

I have a simple hub that I am trying to write a test for with FakeItEasy and the verification of calling the client is not passing. I have the example working in a separate project that uses MOQ and XUnit.

public interface IScheduleHubClientContract
{
    void UpdateToCheckedIn(string id);
}

public void UpdateToCheckedIn_Should_Broadcast_Id()
{
    var hub = new ScheduleHub();
    var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
    var all = A.Fake<IScheduleHubClientContract>();

    var id= "123456789";
    hub.Clients = clients;

    A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
    A.CallTo(() => clients.All).Returns(all);

    hub.UpdateToCheckedIn(id);
}

I'm using Fixie as the Unit Test Framework and it reports:

FakeItEasy.ExpectationException:

Expected to find it once or more but no calls were made to the fake object.

The sample below works in XUnit & MOQ:

    public interface IScheduleClientContract
    {
        void UpdateToCheckedIn(string id);

    }

    [Fact]
    public void UpdateToCheckedIn_Should_Broadcast_Id()
    {
        var hub = new ScheduleHub();
        var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
        var all = new Mock<IScheduleClientContract>();
        hub.Clients = clients.Object;
        all.Setup(m=>m.UpdateToCheckedIn(It.IsAny<string>())).Verifiable();
        clients.Setup(m => m.All).Returns(all.Object);

        hub.UpdateToCheckedIn("id");

        all.VerifyAll();

    }

I'm not sure what I've missed in the conversion?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Kevin LaBranche
  • 20,908
  • 5
  • 52
  • 76

1 Answers1

3

You're doing some steps in a weird (it looks to me, without seeing the innards of your classes) order, and I believe that's the problem.

I think your key problem is that you're attempting to verify that all.UpdateToCheckedIn must have happened before even calling hub.UpdateToCheckedIn. (I don't know for sure that hub.UpdateToCheckedIn calls all.UpdateToCheckedIn, but it sounds reasonable.

There's another problem, where you configure clients.Setup to return all.Object, which happens after you assert the call to all.UpdateToCheckedIn. I'm not sure whether that's necessary or not, but thought I'd mention it.

The usual ordering is

  1. arrange the fakes (and whatever else you need)
  2. act, but exercising the system under test (hub)
  3. assert that expected actions were taken on the fakes (or whatever other conditions you deem necessary for success)

I would have expected to see something more like

// Arrange the fakes
var all = A.Fake<IScheduleHubClientContract>();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
A.CallTo(() => clients.All).Returns(all); // if All has a getter, this could be clients.All = all

// … and arrange the system under test
var hub = new ScheduleHub();
hub.Clients = clients;

// Act, by exercising the system under test
var id = "123456789";
hub.UpdateToCheckedIn(id);

// Assert - verify that the expected calls were made to the Fakes
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • 1
    I think `.Verifiable()` in Moq doesn't immediately verify the call, it just indicates that it should be verified when `VerifyAll` is called. (I kind of like this approach by the way, maybe we should add something like that to FakeItEasy; it avoids repeating the call specification) – Thomas Levesque Aug 18 '18 at 09:37
  • 1
    @ThomasLevesque, you're right about how Moq's `.Verifiable` works. Truth be told, I don't love it. I understand why people like the expediency, but I enjoy the explicitness of knowing where to look for the assertion. And people can always save the specification to a variable if they want. Also note that in the Moq example, there's actually no reuse - `all.Setup` is verifiable, but has no configured behaviour, if I read it right. But I'm happy to wrangle over whether this is a good feature to add over at the FakeItEasy repo! – Blair Conrad Aug 18 '18 at 11:00
  • 1
    Ah, so you won't like the issue I just opened ;) – Thomas Levesque Aug 18 '18 at 12:00
  • Ah... sooo simple, love it! That is exactly the case. I was just copying my MOQ code line for line... but didn't think about the Verifiable/VerifyAll. That's what I get. I knew it was something simple. Brain dead moment, we all get them. :-) The MOQ code is a direct sample from MS's samples on unit testing SignalR hubs and I was on cruise control even more than usual (Friday, end of day.... lol). – Kevin LaBranche Aug 18 '18 at 14:10
  • @BlairConrad - Love FakeItEasy btw!!!! :-) So much easier to read/follow imo... – Kevin LaBranche Aug 18 '18 at 14:17
  • @klabranche, that's nice to hear. I do too. The explicit syntax was one of the things that made me switch to it at work! – Blair Conrad Aug 18 '18 at 19:34
  • @BlairConrad and use it with Fixie Test Framework and you have a match made in heaven! :-) Throw in Shouldly for easier to read assertions and boom, glorious! – Kevin LaBranche Aug 19 '18 at 00:21