2

I'm trying to use FakeItEasy 2.0.0 to fake a property in a simple interface:

public interface IPerson
{
    int Age { set; }
}

Note that I don't have a get accessor. The test I'm trying to write is:

public void SetsAge()
{
    var fakePerson = A.Fake<IPerson>();
    A.CallToSet(() => fakePerson.Age).To(42).MustHaveHappened();
    fakePerson.Age = 42;
}

But the line containing A.CallToSet fails to compile with:

enter image description here

which is fairly self-explanatory, but confusing since I'm not trying to get the property's value.

Do I have to provide a get accessor to get this to compile (even though I don't want a get accessor)? What is the reason that it requires the get accessor in this case (the same compiler error happens when I replace MustHaveHappened with DoesNothing)? Or am I doing something fundamentally wrong?

Or perhaps I shouldn't lose too much sleep over this and do the right thing in the first place?

Community
  • 1
  • 1
WalderFrey
  • 575
  • 2
  • 17
  • A set-only property is usually a code smell. I'd be interested to know why you have this in the first place. – Adam Ralph Jun 14 '16 at 13:32
  • @Adam: The example I've given is only to demonstrate the problem that I was seeing. In reality, I'm trying to create what I suppose would be an MVP architecture in a Winforms application. The view interface has a set-only property to allow the presenter to pass it the object being viewed. In the view, this object is then data bound to UI controls. The presenter responds to property change notifications to update the model. At no time does the view nor the presenter need to a get accessor to query which object was passed to the view, so I omitted it. I hope that makes sense! – WalderFrey Jun 14 '16 at 15:42

1 Answers1

3

Do I have to provide a get accessor to get this to compile?

No, you can use

A.CallTo(fakePerson).Where(call => call.Method.Name == "set_Age" &&
                                   call.GetArgument<int>(0) == 42)
                    .MustHaveHappened();

This is documented in Specifying a call to any method or property.

What is the reason that it requires the get accessor?

The reason is that because you can't use a = in a lamdba expression, there's no easy way to refer to the property setter. In 2.0, we added A.CallToSet to allow you to cheat by using the getter, but of course it only works when there is a getter.

We've not yet come up with an elegant way to refer to a getterless setter, so you have to use the powerful version of A.CallTo above.

Or am I doing something fundamentally wrong?

Well, in addition to the problem with referring to the property, the whole A.CallTo…MustHaveHappend() has to occur after fakePerson.Age = 42, or it will report a failure, because you haven't yet set fakePerson.Age to 42.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • I'm glad. Note that I'd forgotten to check the restriction on the value in my example at first. I've since amended. `call.GetArgument("value")` would also work, if you prefer names to indexes. – Blair Conrad Jun 14 '16 at 11:08