Fake generic method with FakeItEasy without specifying type
Asked Answered
V

1

15

I wonder if there is anyway one can fake up a generic method call, for all possible types (or specified sub-types)?

For example, suppose we have this wonderful IBar interface.

public interface IBar
{
    int Foo<T>();    
}

Can I fake a dependency to this IBar's Foo call, without having to specify T being any specific type?

[TestFixture]
public class BarTests
{
    [Test]
    public void BarFooDoesStuff()
    {
        var expected = 9999999;
        var fakeBar = A.Fake<IBar>();

        A.CallTo(() => fakeBar.Foo<T>()).Returns(expected);

        var response = fakeBar.Foo<bool>();

        Assert.AreEqual(expected, response);
    }
}

Thanks!

Vaseline answered 4/4, 2014 at 14:40 Comment(0)
M
25

I'm not aware of any way to do this directly. I don't think DynamicProxy (which FakeItEasy uses) supports open generic types. However, there's a workaround, if you're interested.

There's a way to specify a call to any method or property on a fake. Check out the Where and WithReturnType bits in this passing test:

[TestFixture]
public class BarTests
{
    [Test]
    public void BarFooDoesStuff()
    {
        var expected = 9999999;
        var fakeBar = A.Fake<IBar>();

        A.CallTo(fakeBar)
            .Where(call => call.Method.Name == "Foo")
            .WithReturnType<int>()
            .Returns(expected);

        var response = fakeBar.Foo<bool>();

        Assert.AreEqual(expected, response);
    }
}

Still, though, I'm curious about the use for this. Do you have an example test that actually uses the faked interface as a dependency?

Memoirs answered 4/4, 2014 at 16:6 Comment(6)
+1 this is a good way to do it, but I'm also unconvinced of the need to set up a fake in this manner. a unit test should generally close the type parameter on a genericAcis
Very nice! I don't have specific examples to show... more for the curiosity whether something like this can be done (easily). Perhaps Reflection can be employed to restrict the generic types in the fake set-up?Vaseline
@AdamRalph yes, but is doesn't necessarily have to do this in a static manner. I for example am using SpecFlow and I have steps like When <type> with Id <id> is retrieved from repository. With the above I don't have to prepare a step binding method for each <type>.Ultraconservative
I just used this to make all my validation helper methods pass by default in unit tests. A.CallTo(validationService).WithReturnType<bool>().Returns(true); I can later override one method with specific behavour if needed.Pyrimidine
If you are using C#6 then you could make it easier to refactor, by using "nameof": A.CallTo(fakeBar).Where(call => call.Method.Name == nameof(fakeBar.Foo)).WithReturnType<int>().Returns(expected);Granular
It's a pretty old answer, but I have an example usage : I have a IExporter using a ISerializer with methods to serialize various objects. In my Exporter tests, I don't care about what the serializer returns, but I don't want it to return an empty string. So I'm using A.CallTo(serializer).WithReturnType<string>().Returns(fixture.Create<string>()); but if I add a non-serializing method to ISerializer later my tests might break.Disappointment

© 2022 - 2024 — McMap. All rights reserved.