Reputation: 24949
versions Castle Windsor 3.3.0.0 Moq 4.2.1507.118
it appears that Moq comes with CallBase setting that, when enabled, delegates calls to any non-setup methods down to base object.
var mock = new Mock<MyService> {CallBase = true};
unfortunately as soon as I register it with Castle Windsor, all non mocked methods are returning a null immediately, underlying logic is no longer called.
Container.Register(Component
.For<MyService>()
.Instance(mock.Object)
.LifeStyle.Singleton
);
I tried a few different lifestyles as well.
so when I do this:
mock.setup(x => x.SomeMethod).Returns(myMockedData);
this works as expected:
Container.Resolve<MyService>().SomeMethod();
but now this returns a null:
Container.Resolve<MyService>().AnotherMethod();
as soon as I remove the mock registration, AnotherMethod starts working as before.
more specific code example
public class Auth : IAuth
{
// mocked succesfully
public IEnumerable<T> AuthorizeData<T>(IEnumerable<T> data) { ... }
// never gets called
public virtual List<User> GetAllUsers() {
return new List<User>{new User{FIRST_NAME = "test"}};
}
}
mock method
protected static Mock<T> GetMock<T>() where T : class {
var mock = new Mock<T> {CallBase = true, DefaultValue = DefaultValue.Mock};
IoC.Container.Register(Component
.For<T>()
.Instance(mock.Object)
.LifeStyle.Transient
);
return mock;
}
mock setup
GetMock<IAuth>().Setup(x => x.AuthorizeData(It.IsAny<IEnumerable<DO>>()))
.Returns((IEnumerable<DO> data) => data); // pass through input data (do not authorize
to sum up again, AuthorizeData is mocked successfully, GetAllUsers() returns an empty list. and original class never gets called
Upvotes: 5
Views: 1938
Reputation: 233347
CallBase
doesn't control how return values are generated. For that, you'll need to set the DefaultValue
property:
var mock = new Mock<MyService> { CallBase = true, DefaultValue = DefaultValue.Mock };
The default value for DefaultValue
(sic.) is DefaultValue.Empty
, so that's the reason you'll need to explicitly set it to DefaultValue.Mock
.
When you do that, the mock
will return other proxy values from methods without explicit setups. If the return value is a concrete type, Moq will attempt to create a value of that type, but it'll only do that if that type has a parameterless constructor. If no parameterless constructor exists, it'll throw an exception when you try to call the method.
You may want to look into turning Castle Windsor into an Auto-Mocking Container.
Based on the comments below, I can't reproduce the issue. Assuming that AuthorizeData
is virtual
(which it isn't above, but which the comments claim), this test passes:
[Fact]
public void Repro()
{
var td = new Mock<Auth>
{
CallBase = true,
DefaultValue = DefaultValue.Mock
};
var container = new WindsorContainer();
container.Register(Component.For<Auth>().Instance(td.Object));
td
.Setup(a => a.AuthorizeData<string>(new string[0]))
.Returns(new[] { "foo", "bar" });
Assert.Equal(
new[] { "foo", "bar" },
container.Resolve<Auth>().AuthorizeData(new string[0]));
Assert.NotEmpty(container.Resolve<Auth>().GetAllUsers());
}
Upvotes: 2