Reputation: 621
Wanting to know if there's a way to mock a virtual method on a concrete class using AutoFixture and NSubstitute. I've been able to do this easily with Moq, as can be seen here:
public class SomeConcreteClass
{
public string MethodA()
{
return MethodB();
}
public virtual string MethodB()
{
return "AAA";
}
}
[TestFixture]
public class SomeConcreteClassTests
{
private IFixture _fixture;
private SomeConcreteClass _someConcreteClass;
[SetUp]
protected void Setup()
{
_fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var someConcreteClassMock = _fixture.Create<Mock<SomeConcreteClass>>();
_someConcreteClass = someConcreteClassMock.Object;
someConcreteClassMock.CallBase = true;
}
[Test]
public void SomeScenario()
{
Mock.Get(_someConcreteClass).Setup(m => m.MethodB()).Returns("BBB");
var actual = _someConcreteClass.MethodA();
actual.ShouldBe("BBB");
}
}
Upvotes: 3
Views: 1219
Reputation: 233277
This is best achieved if you use AutoFixture's support for Parametrised Tests, here illustrated using xUnit.net (but, IIRC, there's similar support for NUnit):
[Theory, AutoNSubstituteData]
public void ImplicitSubtituteViaAttribute([Substitute]SomeConcreteClass scc)
{
scc.MethodB().Returns("BBB");
var actual = scc.MethodB();
Assert.Equal("BBB", actual);
}
Using the [Substitute]
attribute enables you to explicitly tell AutoFixture that, although you asked for a concrete class, it should create it via NSubstitute so that you can override any virtual members it might have.
AutoNSubstituteData
is defined like this:
public class AutoNSubstituteDataAttribute : AutoDataAttribute
{
public AutoNSubstituteDataAttribute() :
base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
{
}
}
AutoDataAttribute
comes from AutoFixture.Xunit2, but if you prefer NUnit over xUnit.net, you should be able to use AutoFixture.NUnit3 instead.
Otherwise, I'm not sure you can achieve exactly the same result as with AutoFixture.AutoMoq. In this degenerate example, you can do this:
[Fact]
public void ImperativeWorkaround()
{
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
fixture.Register(() => Substitute.For<SomeConcreteClass>());
var scc = fixture.Create<SomeConcreteClass>();
scc.MethodB().Returns("BBB");
var actual = scc.MethodB();
Assert.Equal("BBB", actual);
}
This is, however, fairly pointless, as you could just as well have written this:
[Fact]
public void Reduction()
{
var scc = Substitute.For<SomeConcreteClass>();
scc.MethodB().Returns("BBB");
var actual = scc.MethodB();
Assert.Equal("BBB", actual);
}
In other words, AutoFixture doesn't actually do anything in that workaround.
I could imagine that the real issue is that in real usage, the concrete class in question has other members or constructor data that you wish to fill with data. The problem is that due to the way NSubstitute is designed, I'm not aware of any way you can declaratively ask for a 'substitute'; you'll have to use the Substitute.For
method, which then completely short-circuits AutoFixture's ability to hook into the process and add its own behaviour.
With Moq, this is possible because in the OP, you're not asking AutoFixture for a SomeConcreteClass
object, but rather for a Mock<SomeConcreteClass>
, and that enables AutoFixture to distinguish.
In other words, Moq follows the Zen of Python that explicit is better than implicit, and that makes it extensible to a degree not easily achieved with NSubstitute. For that reason, I've always considered Moq to have the better API.
Upvotes: 4