1

I'm trying to get FakeItEasy 1.25.3 to throw an exception on a property; the setter test works fine but the getter does not throw an exception as expected. What am I doing wrong?

public interface IMisc
{
    int IntProperty { get; set; }
}

// Setter throws exception as expected.
[Test]
public void Property_Setter_Throws()
{
    var driver = A.Fake<IMisc>();
    A.CallTo(driver).Where(call => call.Method.Name == "set_IntProperty")
          .Throws(new Exception());
    var i = driver.IntProperty; 
    Assert.That( delegate { driver.IntProperty = 3; }, Throws.Exception);
}

// Getter does not throw exception as expected.
[Test]
public void Property_Getter_Throws()
{
    var driver = A.Fake<IMisc>();
    A.CallTo(driver).Where(call => call.Method.Name == "get_IntProperty")
          .Throws(new Exception());
    driver.IntProperty = 3;
    Assert.That(delegate { var i = driver.IntProperty; }, Throws.Exception);
}
  • 1
    Try to comment this line `driver.IntProperty = 3;` – Yacoub Massad May 15 '16 at 21:48
  • @YacoubMassad That works, thanks. So I'm guessing using the property setter will remove the call rule for the property getter? –  May 15 '16 at 21:50
  • Yes. When you set a property value, it sets up the getter to return that value when invoked. – Yacoub Massad May 15 '16 at 21:51
  • 1
    Technically it doesn't remove the call rule for the getter, but it adds an additional rule, which takes precedence, under FakeItEasy's "I'll do the last thing you told me" policy. The effect looks pretty much the same, though. @YacoubMassad gave a great answer, and it absolutely correct, but I'm going to augment it with a little more information that may be useful during the transition to FakeItEasy 2.0 if/when you make it. – Blair Conrad May 16 '16 at 10:58

1 Answers1

2

It is this line:

driver.IntProperty = 3;

that is causing your problem. What it does basically is configuring the getter to return the value 3 when it is invoked.

This is because IntProperty is a Read/Write property. See this for more information.

Quoting from the link above:

Although you can explicitly specify the return value for a called property getter, there's an easier, more intuitive way to work with read/write properties. By default, any fakeable property that has both a set and get accessor behaves like you might expect. Setting a value and then getting the value returns the value that was set.

In addition, note that the behaviour you saw will change with FakeItEasy 2.0, due to the fix for magic property get followed by another get returns different object when property type is not fakeable. With that change, your two tests would've failed in about the same way - Property_Setter_Throws would also fail, because using the getter for driver.IntProperty would prime FakeItEasy to return the same return value instance in the future (it's setting up an automatic property rule).

And as a further bit of information that may help you in the future, you may enjoy using typesafe methods for setting up property behaviour:

A.CallTo(driver).Where(call => call.Method.Name == "get_IntProperty")
                .Throws(new Exception());

can become

A.CallTo(() => driver.IntProperty).Throws(new Exception());

(and in FakeItEasy 2.0, there is a similar method for configuring property setters):

A.CallToSet(() => driver.IntProperty).Throws(new Exception());
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62