Using FakeItEasy it is possible to create a dummy type object that takes generic type parameters

I have the following test:

[Fact]
public void StartProgram_CallsZoneProgramStart()
{
    var zone = A.Fake<Zone>();
    zone.StartProgram();
    A.CallTo(() => zone.ZoneProgram.Start(null, A.Dummy<ActionBlock<InterruptInfo>>())).MustHaveHappened(Repeated.Exactly.Once);
}

      

It creates a dummy type ActionBlock<InterruptInfo>

that is passed to the MustHaveHappened call. zone.StartProgram definitely calls the zone.ZoneProgram.Start method, but this call doesn't see FakeItEasy. It returns the following error message:

Assertion failed for the following call:
  ZoneLighting.ZoneProgramNS.ZoneProgram.Start(<NULL>, ActionBlock\`1 Id=1)
Expected to find it exactly once but found it #0 times among the calls:
  1: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: Faked ZoneLighting.ZoneProgramNS.InputStartingValues, interruptQueue: ActionBlock`1 Id=2)
  2: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: <NULL>, interruptQueue: ActionBlock`1 Id=2)

      

As you can see from the error message, the mapping ID of ActionBlocks is different (1 and 2), so it cannot see that the call is made. My question is, why is the dummy id ActionBlock = 1? I thought it was a dummy object, it shouldn't contain any specific details in it like ID, etc. Is it because typical types cannot be empty?

I saw something similar here: https://github.com/FakeItEasy/FakeItEasy/issues/402

But I could not understand whether he was talking about the same thing or not. Any help would be greatly appreciated.

+3


source to share


1 answer


I'm not familiar with ActionBlock

s, so I don't know where they get the values ​​from Id

, but I think I can shed some light on what's going on in your test.

First, I think you are confused about what it is Dummy

. If so, don't feel bad. They can be a little confusing. From Dummy documentation , Dummy

Dummy is an object that FakeItEasy can provide when an object of a certain type is required, but the actual behavior of the object does not matter.

They are mainly used by FakeItEasy itself when it needs to create an object to feed to class constructors (we'll learn about that later) or when it needs to return a non-fake object from a method or property. Rarely do end users have to create them.

A Dummy is a real object (it should be - otherwise, how can we do something about it?). It must have in itself some specific details that are of its type (in this case ActionBlock<InterruptInfo>

). There are no restrictions on the typical types of Dummying.

Looking at the docs for how a Dummy is created , we see that since ActionBlock<InterruptInfo>

it probably doesn't have a custom one IDummyDefinition

available (do you have one?) And it's not a task, and it's not tampered with (because the class is sealed), then the Dummy is created by calling one of the ActionBlock constructors , with the Mannequins turning into safits for each of the arguments.

I think ActionBlocks have IDs. How they are assigned I have no idea, but if they are good IDs, then it looks like we have two different ActionBlock<InterruptInfo>

s: one is represented in zone.StartProgram

, and Dummy is in the test.

The ActionBlocks documentation assumes it does not override Equals

, so a comparison will be made and the two ActionBlocks (Dummy and the one used in the production code) do not match. This is why FakeItEasy does not recognize the challenge.



If you were just trying to figure out if any call was made zone.ZoneProgram.Start

with the first argument null

and the second argument with some ActionBlock, I think you could use:

A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored))
            .MustHaveHappened(Repeated.Exactly.Once);

      

( Ignored

Can also be shortened to _

. More on ignoring argument values if you're so inclined.)

This may help you overcome your immediate problem, although I have two concerns about this:

  • It looks like it zone.ZoneProgram.Start

    gets called twice, not "Exactly.Once", but I'm sure you can handle it, and
  • In general, tampering with a test object is considered an anti-pattern. Typically one will inject fake dependencies into the production code under test. I'm not saying this won't work, but sometimes it can be confusing. However, this could be a problem for another day after the current issue is resolved.

I hope this helps a little.

Oh, and you asked about the 402 error. This problem is about giving users more power in defining customization classes that will dictate how dummies are created. If you haven't extended the class, IDummyDefinition

or DummyDefinition

it is probably not up to date at the moment.

+3


source







All Articles