I tried in vain to mock a top-level (not part of any section) configuration value (.NET Core's IConfiguration). For example, neither of these will work (using NSubstitute, but it would be the same with Moq or any mock package I believe):
var config = Substitute.For<IConfiguration>();
config.GetValue<string>(Arg.Any<string>()).Returns("TopLevelValue");
config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue"); // nope
// non generic overload
config.GetValue(typeof(string), Arg.Any<string>()).Returns("TopLevelValue");
config.GetValue(typeof(string), "TopLevelKey").Should().Be("TopLevelValue"); // nope
In my case, I also need to call GetSection from this same config instance.
You can use an actual Configuration instance with in-memory data.
//Arrange
var inMemorySettings = new Dictionary<string, string> {
{"TopLevelKey", "TopLevelValue"},
{"SectionName:SomeKey", "SectionValue"},
//...populate as needed for the test
};
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(inMemorySettings)
.Build();
//...
Now it is a matter of using the configuration as desired to exercise the test
//...
string value = configuration.GetValue<string>("TopLevelKey");
string sectionValue = configuration.GetSection("SectionName").GetValue<string>("SomeKey");
//...
Reference: Memory Configuration Provider
I do not have idea about NSubstitute, but this is how we can do in Moq.
Aproach is same in either cases.
GetValue<T>() internally makes use of GetSection().
You can Mock GetSection and return your Own IConfigurationSection.
This includes two steps.
1). Create a mock for IConfigurationSection (mockSection) & Setup .Value Property to return your desired config value.
2). Mock .GetSection on Mock< IConfiguration >, and return the above mockSection.Object
Mock<IConfigurationSection> mockSection = new Mock<IConfigurationSection>();
mockSection.Setup(x=>x.Value).Returns("ConfigValue");
Mock<IConfiguration> mockConfig = new Mock<IConfiguration>();
mockConfig.Setup(x=>x.GetSection(It.Is<string>(k=>k=="ConfigKey"))).Returns(mockSection.Object);
Mock IConfiguration
Mock<IConfiguration> config = new Mock<IConfiguration>();
SetupGet
config.SetupGet(x => x[It.Is<string>(s => s == "DeviceTelemetryContainer")]).Returns("testConatiner");
config.SetupGet(x => x[It.Is<string>(s => s == "ValidPowerStatus")]).Returns("On");
IConfiguration.GetSection<T> must be mocked indirectly. I don't fully understand why because NSubstitute, if I understand correctly, creates its own implementation of an interface you're mocking on the fly (in memory assembly). But this seems to be the only way it can be done. Including a top-level section along with a regular section.
var config = Substitute.For<IConfiguration>();
var configSection = Substitute.For<IConfigurationSection>();
var configSubSection = Substitute.For<IConfigurationSection>();
configSubSection.Key.Returns("SubsectionKey");
configSubSection.Value.Returns("SubsectionValue");
configSection.GetSection(Arg.Is("SubsectionKey")).Returns(configSubSection);
config.GetSection(Arg.Is("TopLevelSectionName")).Returns(configSection);
var topLevelSection = Substitute.For<IConfigurationSection>();
topLevelSection.Value.Returns("TopLevelValue");
topLevelSection.Key.Returns("TopLevelKey");
config.GetSection(Arg.Is<string>(key => key != "TopLevelSectionName")).Returns(topLevelSection);
// GetValue mocked indirectly.
config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue");
config.GetSection("TopLevelSectionName").GetSection("SubsectionKey").Value.Should().Be("SubsectionValue");
I could imagine in some rare scenarios it is needed but, in my humble opinion, most of the time, mocking IConfiguration highlight a code design flaw.
You should rely as much as possible to the option pattern to provide a strongly typed access to a part of your configuration. Also it will ease testing and make your code fail during startup if your application is misconfigured (instead than at runtime when the code reading IConfiguration is executed).
If you really(really) need to mock it then I would advice to not mock it but fake it with an in-memory configuration as explained in #Nkosi's answer
While Nkosi's answer works great for simple structures, sometimes you want to be able to have more complex objects (like arrays) without repeating the whole section path and to be able to use the expected types themselves. If you don't really care too much about performance (and should you in your unit tests?) then this extension method might be helpful.
public static void AddObject(this IConfigurationBuilder cb, object model) {
cb.AddJsonStream(new MemoryStream(Encoding.UTF8.GetString(JsonConvert.SerializeObject(model))));
}
And then use it like this
IConfiguration configuration = new ConfigurationBuilder()
.AddObject(new {
SectionName = myObject
})
.Build();
Use SetupGet method to mock the Configuration value and return any string.
var configuration = new Mock<IConfiguration>();
configuration.SetupGet(x => x[It.IsAny<string>()]).Returns("the string you want to return");
We need to mock IConfiguration.GetSection wichs is executed within GetValue extension method.
You inject the IConfiguration:
private readonly Mock<IConfiguration> _configuration;
and the in the //Arrange Section:
_configuration.Setup(c => c.GetSection(It.IsAny())).Returns(new Mock().Object);
It worked like a charm for me.
I've found this solution to work reliably for me for my XUnit C# tests & corresponding C# code:
In Controller
string authConnection = this._config["Keys:AuthApi"] + "/somePathHere/Tokens/jwt";
In XUnit Test
Mock<IConfiguration> mockConfig = new Mock<IConfiguration>();
mockConfig.SetupGet(x => x[It.Is<string>(s => s == "Keys:AuthApi")]).Returns("some path here");
Related
i try to use a custom protobuf-net RuntimeTypeModel with the protobuf-net grpc client library.
What I understand so far, I need to to use the ClientFactory and set a binder-configuration which references my RuntimeTypeModel-Instance.
var binderConfig = BinderConfiguration.Create(new List<MarshallerFactory> {
ProtoBufMarshallerFactory.Create(_runtimeTypeModel)
});
var clientFactory = ClientFactory.Create(binderConfig)
This is working, if i create the client and the underlying grpc-channel every time myself.
Now, I want to use the GrpcClientFactory via DI provided by the nuget package protobuf-net.Grpc.ClientFactory
I don't know, how to configure the ClientFactory to use my custom RuntimeTypeModel. In my startup I tried the following:
.AddCodeFirstGrpcClient<IMyGrpcService>(o =>
{
o.Address = new Uri("https://localhost:5001");
o.Creator = (callInvoker) =>
{
var servicesProvider = services.BuildServiceProvider();
var binderConfig = BinderConfiguration.Create(new List<MarshallerFactory> {
ProtoBufMarshallerFactory.Create(servicesProvider.GetService<RuntimeTypeModel>())
});
var clientFactory = ClientFactory.Create(binderConfig);
return clientFactory.CreateClient<IMyGrpcService>(callInvoker);
};
});
I can use IMyGrpcService in my controller classes and get a valid instance. But the o.Creator delegate is never called and the wrong runtimeTypeModel is used.
What is wrong with this approach?
Thanks.
Toni
You need to register the ClientFactory with the DI layer:
services.AddSingleton<ClientFactory>(clientFactory)
Now it should discover it correctly. You should not need to set the Creator.
(note: it doesn't specifically need to be a singleton, but: that should work)
I'm trying out Moq and the builder pattern to set up services for testing CRM plugins. On the builder I have a ConfigureMock<T>(Expression<Action<Mock<T>>>) to inject individual configurations. My problem is that once a service is .Setup(), I would like to get the entity the service worked on via .Callback<Entity>(), but I cannot assign it to a local variable in the test, because I can't do assignments in the callback expression.
Here is the config:
private readonly Dictionary<Type, object> MockServices = new Dictionary<Type, object>();
public PluginContextBuilder ConfigMock<T>(Expression<Action<Mock<T>>> setupConfig) where T : class
{
object svc = null;
if (MockServices.TryGetValue(typeof(T), out svc))
{
var mockSvc = (Mock<T>) svc;
Action<Mock<T>> setup = setupConfig.Compile();
setup(mockSvc);
}
return this;
}
And here's an example how I would like to configure in the test (but will not compile):
var createdFanClub = null;
var context = new PluginContextBuilder()
.ConfigMock<IOrganizationService>(c =>
c.Setup(s =>
s.Create(It.IsAny<Entity>()))
.Returns(fanclubGuid))
.Callback<Entity>(a => createdFanClub = a))
If I create an additional Action<Entity> which does the assignment, it works, but I don't think it's practical, in case I have multiple entities, I will need to make just as many assignments for them:
Entity createdFanClub = null;
Action<Entity> assign = a => createdFanClub = a;
var context = new PluginContextBuilder()
.ConfigMock<IOrganizationService>(c =>
c.Setup(s =>
s.Create(It.IsAny<Entity>()))
.Returns(fanclubGuid))
.Callback<Entity>(assign))
Not sure what you try to accomplish. If the goal is to have a builder, which has a handle to all the mocks needed, then why not just return the mock itself, and configure it as one normally will do:
builder.GetMock<IOrganizationService>().Setup....
That will prevent you to chain calls on the same builder (as I see you are trying to do), but it's not a big trade-off, and will simplify your setups.
Given the following open generic deocrator chain using SimpleInjector:
container.RegisterManyForOpenGeneric(typeof(IHandleQuery<,>), assemblies);
container.RegisterDecorator(
typeof(IHandleQuery<,>),
typeof(ValidateQueryDecorator<,>)
);
container.RegisterSingleDecorator(
typeof(IHandleQuery<,>),
typeof(QueryLifetimeScopeDecorator<,>)
);
container.RegisterSingleDecorator(
typeof(IHandleQuery<,>),
typeof(QueryNotNullDecorator<,>)
);
With SimpleInjector 2.4.0, I was able to unit test this to assert the decoration chain using the following code:
[Fact]
public void RegistersIHandleQuery_UsingOpenGenerics_WithDecorationChain()
{
var instance = Container
.GetInstance<IHandleQuery<FakeQueryWithoutValidator, string>>();
InstanceProducer registration = Container.GetRegistration(
typeof(IHandleQuery<FakeQueryWithoutValidator, string>));
instance.ShouldNotBeNull();
registration.Registration.ImplementationType
.ShouldEqual(typeof(HandleFakeQueryWithoutValidator));
registration.Registration.Lifestyle.ShouldEqual(Lifestyle.Transient);
var decoratorChain = registration.GetRelationships()
.Select(x => new
{
x.ImplementationType,
x.Lifestyle,
})
.Reverse().Distinct().ToArray();
decoratorChain.Length.ShouldEqual(3);
decoratorChain[0].ImplementationType.ShouldEqual(
typeof(QueryNotNullDecorator<FakeQueryWithoutValidator, string>));
decoratorChain[0].Lifestyle.ShouldEqual(Lifestyle.Singleton);
decoratorChain[1].ImplementationType.ShouldEqual(
typeof(QueryLifetimeScopeDecorator<FakeQueryWithoutValidator, string>));
decoratorChain[1].Lifestyle.ShouldEqual(Lifestyle.Singleton);
decoratorChain[2].ImplementationType.ShouldEqual(
typeof(ValidateQueryDecorator<FakeQueryWithoutValidator, string>));
decoratorChain[2].Lifestyle.ShouldEqual(Lifestyle.Transient);
}
After updating to SimpleInjector 2.6.1, this unit test fails. It seems that InstanceProducer.Registration.ImplementationType now returns the first decoration handler rather than the decorated handler (meaning, it returns typeof(QueryNotNullDecorator<HandleFakeQueryWithoutValidator,string>) instead of typeof(HandleFakeQueryWithoutValidator).
Also, InstanceProducer.GetRelationships() no longer returns all of the decorators in the chain. it also only returns the first decorator.
Is this a bug and, if not, how can we unit test open generic decorator chains using SimpleInjector 2.6.1+?
The detail available for the dependency graph has been greatly improved in 2.6. You can achieve the same thing with this code:
[Fact]
public void RegistersIHandleQuery_UsingOpenGenerics_WithDecorationChain()
{
var container = this.ContainerFactory();
var instance = container
.GetInstance<IHandleQuery<FakeQueryWithoutValidator, string>>();
var registration = (
from currentRegistration in container.GetCurrentRegistrations()
where currentRegistration.ServiceType ==
typeof(IHandleQuery<FakeQueryWithoutValidator, string>)
select currentRegistration.Registration)
.Single();
Assert.Equal(
typeof(QueryNotNullDecorator<FakeQueryWithoutValidator, string>),
registration.ImplementationType);
Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);
registration = registration.GetRelationships().Single().Dependency.Registration;
Assert.Equal(
typeof(QueryLifetimeScopeDecorator<FakeQueryWithoutValidator, string>),
registration.ImplementationType);
Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);
registration = registration.GetRelationships().Single().Dependency.Registration;
Assert.Equal(
typeof(ValidateQueryDecorator<FakeQueryWithoutValidator, string>),
registration.ImplementationType);
Assert.Equal(Lifestyle.Transient, registration.Lifestyle);
}
You can find more information here
Please note: I think you have a captive dependency - you have a transient handler inside of a singleton decorator ...
[Fact]
public void Container_Always_ContainsNoDiagnosticWarnings()
{
var container = this.ContainerFactory();
container.Verify();
var results = Analyzer.Analyze(container);
Assert.False(results.Any());
}
Qujck is right. We greatly improved the way registrations and KnownDependency graphs are built, especially to improve diagnostics and to make it easier for users to query the registrations. So this is not a bug; this is a breaking change. We however didn't expect anyone to be affected by this and that's why we made the change in a minor release. I'm sorry you had to stumble upon this change, but at least it's just test code that breaks.
In previous versions the graph of KnownDependency objects was flattened when decorators where added. This made querying and visualising the object graph hard. In v2.6, from perspective of the diagnostic API, it is as if a decorator is a 'real' registration. This means that the InstanceProducer and Registration objects now show the real type that is returned and its lifestyle.
Much clearer, but a breaking change in the diagnostic API.
The short takeaway now that the solution has been found:
AutoFixture returns frozen the mock just fine; my sut that was also generated by AutoFixture just had a public property with a local default that was important for the test and that AutoFixture set to a new value. There is much to learn beyond that from Mark's answer.
Original question:
I started trying out AutoFixture yesterday for my xUnit.net tests that have Moq all over them. I was hoping to replace some of the Moq stuff or make it easier to read, and I'm especially interested in using AutoFixture in the SUT Factory capacity.
I armed myself with a few of Mark Seemann's blog posts on AutoMocking and tried to work from there, but I didn't get very far.
This is what my test looked like without AutoFixture:
[Fact]
public void GetXml_ReturnsCorrectXElement()
{
// Arrange
string xmlString = #"
<mappings>
<mapping source='gcnm_loan_amount_min' target='gcnm_loan_amount_min_usd' />
<mapping source='gcnm_loan_amount_max' target='gcnm_loan_amount_max_usd' />
</mappings>";
string settingKey = "gcCreditApplicationUsdFieldMappings";
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
ITracingService tracing = new Mock<ITracingService>().Object;
XElement expectedXml = XElement.Parse(xmlString);
IMappingXml sut = new SettingMappingXml(settings, tracing);
// Act
XElement actualXml = sut.GetXml();
// Assert
Assert.True(XNode.DeepEquals(expectedXml, actualXml));
}
The story here is simple enough - make sure that SettingMappingXml queries the ISettings dependency with the correct key (which is hard coded/property injected) and returns the result as an XElement. The ITracingService is relevant only if there's an error.
What I was trying to do is get rid of the need to explicitly create the ITracingService object and then manually inject the dependencies (not because this test is too complex, but because it is simple enough to try things out and understand them).
Enter AutoFixture - first attempt:
[Fact]
public void GetXml_ReturnsCorrectXElement()
{
// Arrange
IFixture fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
string xmlString = #"
<mappings>
<mapping source='gcnm_loan_amount_min' target='gcnm_loan_amount_min_usd' />
<mapping source='gcnm_loan_amount_max' target='gcnm_loan_amount_max_usd' />
</mappings>";
string settingKey = "gcCreditApplicationUsdFieldMappings";
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
fixture.Inject(settings);
XElement expectedXml = XElement.Parse(xmlString);
IMappingXml sut = fixture.CreateAnonymous<SettingMappingXml>();
// Act
XElement actualXml = sut.GetXml();
// Assert
Assert.True(XNode.DeepEquals(expectedXml, actualXml));
}
I would expect CreateAnonymous<SettingMappingXml>(), upon detection of the ISettings constructor parameter, to notice that a concrete instance has been registered for that interface and inject that - however, it doesn't do that but instead creates a new anonymous implementation.
This is especially confusing as fixture.CreateAnonymous<ISettings>() does indeed return my instance -
IMappingXml sut = new SettingMappingXml(fixture.CreateAnonymous<ISettings>(), fixture.CreateAnonymous<ITracingService>());
makes the test perfectly green, and this line is exactly what I had expected AutoFixture to do internally when instantiating SettingMappingXml.
Then there's the concept of freezing a component, so I went ahead just freezing the mock in the fixture instead of getting the mocked object:
fixture.Freeze<Mock<ISettings>>(f => f.Do(m => m.Setup(s => s.Get(settingKey)).Returns(xmlString)));
Sure enough this works perfectly fine - as long as I call the SettingMappingXml constructor explicitly and don't rely on CreateAnonymous().
Simply put, I don't understand why it works the way it apparently does, as it goes against any logic I can conjure up.
Normally I would suspect a bug in the library, but this is something so basic that I'm sure others would have run into this and it would long have been found and fixed. What's more, knowing Mark's assiduous approach to testing and DI, this can't be unintentional.
That in turn means I must be missing something rather elementary. How can I have my SUT created by AutoFixture with a preconfigured mocked object as a dependency? The only thing I'm sure about right now is that I need the AutoMoqCustomization so I don't have to configure anything for the ITracingService.
AutoFixture/AutoMoq packages are 2.14.1, Moq is 3.1.416.3, all from NuGet. .NET version is 4.5 (installed with VS2012), behavior is the same in VS2012 and 2010.
While writing this post, I discovered that some people were having problems with Moq 4.0 and assembly binding redirects, so I meticulously purged my solution of any instances of Moq 4 and had Moq 3.1 installed by installing AutoFixture.AutoMoq into "clean" projects. However, the behavior of my test remains unchanged.
Thank you for any pointers and explanations.
Update: Here's the constructor code Mark asked for:
public SettingMappingXml(ISettings settingSource, ITracingService tracing)
{
this._settingSource = settingSource;
this._tracing = tracing;
this.SettingKey = "gcCreditApplicationUsdFieldMappings";
}
And for completeness, the GetXml() method looks like this:
public XElement GetXml()
{
int errorCode = 10600;
try
{
string mappingSetting = this._settingSource.Get(this.SettingKey);
errorCode++;
XElement mappingXml = XElement.Parse(mappingSetting);
errorCode++;
return mappingXml;
}
catch (Exception e)
{
this._tracing.Trace(errorCode, e.Message);
throw;
}
}
SettingKey is just an automatic property.
Assuming that the SettingKey property is defined as follows, I can now reproduce the issue:
public string SettingKey { get; set; }
What happens is that the Test Doubles injected into the SettingMappingXml instance are perfectly fine, but because the SettingKey is writable, AutoFixture's Auto-properties feature kicks in and modifies the value.
Consider this code:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var sut = fixture.CreateAnonymous<SettingMappingXml>();
Console.WriteLine(sut.SettingKey);
This prints something like this:
SettingKey83b75965-2886-4308-bcc4-eb0f8e63de09
Even though all the Test Doubles are properly injected, the expectation in the Setup method isn't met.
There are many ways to address this issue.
Protect invariants
The proper way to resolve this issue is to use the unit test and AutoFixture as a feedback mechanism. This is one of the key points in GOOS: problems with unit tests are often a symptom about a design flaw rather than the fault of the unit test (or AutoFixture) itself.
In this case it indicates to me that the design isn't fool-proof enough. Is it really appropriate that a client can manipulate the SettingKey at will?
As a bare minimum, I would recommend an alternative implementation like this:
public string SettingKey { get; private set; }
With that change, my repro passes.
Omit SettingKey
If you can't (or won't) change your design, you can instruct AutoFixture to skip setting the SettingKey property:
IMappingXml sut = fixture
.Build<SettingMappingXml>()
.Without(s => s.SettingKey)
.CreateAnonymous();
Personally, I find it counterproductive to have to write a Build expression every time I need an instance of a particular class. You can decouple how the SettingMappingXml instance are created from the actual instantiation:
fixture.Customize<SettingMappingXml>(
c => c.Without(s => s.SettingKey));
IMappingXml sut = fixture.CreateAnonymous<SettingMappingXml>();
To take this further, you can encapsulate that Customize method call in a Customization.
public class SettingMappingXmlCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<SettingMappingXml>(
c => c.Without(s => s.SettingKey));
}
}
This requires you to create your Fixture instance with that Customization:
IFixture fixture = new Fixture()
.Customize(new SettingMappingXmlCustomization())
.Customize(new AutoMoqCustomization());
Once you get more than two or three Customizations to chain, you may get tired of writing that method chain all the time. It's time to encapsulate those Customizations into a set of conventions for your particular library:
public class TestConventions : CompositeCustomization
{
public TestConventions()
: base(
new SettingMappingXmlCustomization(),
new AutoMoqCustomization())
{
}
}
This enables you to always create the Fixture instance like this:
IFixture fixture = new Fixture().Customize(new TestConventions());
The TestConventions gives you a central place where you can go and occasionally modify your conventions for the test suite when you need to do so. It reduces the maintainability tax of your unit tests and helps keep the design of your production code more consistent.
Finally, since it looks as though you are using xUnit.net, you could utilize AutoFixture's xUnit.net integration, but before you do that you'd need to use a less imperative style of manipulating the Fixture. It turns out that the code which creates, configures and injects the ISettings Test Double is so idiomatic that it has a shortcut called Freeze:
fixture.Freeze<Mock<ISettings>>()
.Setup(s => s.Get(settingKey)).Returns(xmlString);
With that in place, the next step is to define a custom AutoDataAttribute:
public class AutoConventionDataAttribute : AutoDataAttribute
{
public AutoConventionDataAttribute()
: base(new Fixture().Customize(new TestConventions()))
{
}
}
You can now reduce the test to the bare essentials, getting rid of all the noise, enabling the test to succinctly express only what matters:
[Theory, AutoConventionData]
public void ReducedTheory(
[Frozen]Mock<ISettings> settingsStub,
SettingMappingXml sut)
{
string xmlString = #"
<mappings>
<mapping source='gcnm_loan_amount_min' target='gcnm_loan_amount_min_usd' />
<mapping source='gcnm_loan_amount_max' target='gcnm_loan_amount_max_usd' />
</mappings>";
string settingKey = "gcCreditApplicationUsdFieldMappings";
settingsStub.Setup(s => s.Get(settingKey)).Returns(xmlString);
XElement actualXml = sut.GetXml();
XElement expectedXml = XElement.Parse(xmlString);
Assert.True(XNode.DeepEquals(expectedXml, actualXml));
}
Other options
To make the original test pass, you could also just switch off Auto-properties entirely:
fixture.OmitAutoProperties = true;
In the first test you can create an instance of the Fixture class with the AutoMoqCustomization applied:
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
Then, the only changes are:
Step 1
// The following line:
Mock<ISettings> settingsMock = new Mock<ISettings>();
// Becomes:
Mock<ISettings> settingsMock = fixture.Freeze<Mock<ISettings>>();
Step 2
// The following line:
ITracingService tracing = new Mock<ITracingService>().Object;
// Becomes:
ITracingService tracing = fixture.Freeze<Mock<ITracingService>>().Object;
Step 3
// The following line:
IMappingXml sut = new SettingMappingXml(settings, tracing);
// Becomes:
IMappingXml sut = fixture.CreateAnonymous<SettingMappingXml>();
That's it!
Here is how it works:
Internally, Freeze creates an instance of the requested type (e.g. Mock<ITracingService>) and then injects it so it will always return that instance when you request it again.
This is what we do in Step 1 and Step 2.
In Step 3 we request an instance of the SettingMappingXml type which depends on ISettings and ITracingService. Since we use Auto Mocking, the Fixture class will supply mocks for these interfaces. However, we have previously injected them with Freeze so the already created mocks are now automatically supplied.
I am starting a new project with NHibernate, ASP.NET MVC 2.0 and StructureMap and using NUnit and Moq for testing. For each of my controllers I have a single public constructor into which an ISession is being injected. The application itself works just fine, but in terms of unit testing I essentially have to mock an ISession in order to test the controllers.
When I attempt to Mock the ISession with MOQ i get the following error message:
Only property accesses are supported
in intermediate invocations
It appears that my problem is expecting List of users from the framework CreateQuery method but after googling the issue I am now clearer.
I have two questions:
1) Is this the WRONG way to mock dependency injection of an ISession
2) Is there a way to modify the code so that it can successfully return my list
[Test]
public void DummyTest()
{
var mock = new Mock<ISession>();
var loc = new Mock<User>();
loc.SetupGet(x => x.ID).Returns(2);
loc.SetupGet(x => x.FirstName).Returns("John");
loc.SetupGet(x => x.LastName).Returns("Peterson");
var lst = new List<User> {loc.Object};
mock.Setup(framework => framework.CreateQuery("from User").List<User>()).Returns(lst);
var controller = new UsersController(mock.Object);
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result.ViewData);
}
Please note, I am pretty sure I could just create a hard-coded list of users (rather than mocking an individual User and adding it to a list) but figured I'd leave the code as I have it right now.
Also, the Index action of this particular controller essentially executes the CreateQuery call mimicked above to return all users in the database. This is a contrived example - don't read anything into the details.
Thanks in advance for your help
Edit: In reply to the below comment, I am adding the stacktrace for the error. Also, all properties on the User class are virtual.
TestCase
'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView'
failed: System.NotSupportedException :
Only property accesses are supported
in intermediate invocations on a
setup. Unsupported expression
framework.CreateQuery("from User").
at
Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression
m) at
Moq.ExpressionVisitor.Visit(Expression
exp) at
Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression
m) at
Moq.ExpressionVisitor.Visit(Expression
exp) at
Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(Expression
expression) at
Moq.Mock.GetInterceptor(LambdaExpression
lambda, Mock mock) at
Moq.Mock.<>c__DisplayClass122.<Setup>b__11()
at Moq.PexProtector.Invoke[T](Func1
function) at
Moq.Mock.Setup[T1,TResult](Mock mock,
Expression1 expression) at
Moq.Mock1.Setup[TResult](Expression`1
expression)
Controllers\UserControllerTest.cs(29,0):
at
Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()
Below is the solution I came up with which seems to work perfectly. Again, I am not testing NHibernate and I am not testing the database - I simply want to test the controllers which depend on NHibernate. The issue with the initial solution appears to be the fact that I was calling a Method as well as reading the List member of the session in the MOQ setup call. I broke up these calls by breaking the solution into a QueryMock and a Session Mock (create query returns an IQuery object). A transaction mock was also necessary as it is a dependency (in my case) of the session...
[Test]
public void DummyTest()
{
var userList = new List<User>() { new User() { ID = 2, FirstName = "John", LastName = "Peterson" } };
var sessionMock = new Mock<ISession>();
var queryMock = new Mock<IQuery>();
var transactionMock = new Mock<ITransaction>();
sessionMock.SetupGet(x => x.Transaction).Returns(transactionMock.Object);
sessionMock.Setup(session => session.CreateQuery("from User")).Returns(queryMock.Object);
queryMock.Setup(x => x.List<User>()).Returns(userList);
var controller = new UsersController(sessionMock.Object);
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result.ViewData);
}
Rather than mocking the Session, one might consider setting up a different Configuration for unit-tests. This unit-testing Configuration uses a fast, in-process database like SQLite or Firebird. In the fixture setup, you create a new test database completely from scratch, run the scripts to set up the tables, and create a set of initial records. In the per-test setup, you open a transaction and in the post-test teardown, you rollback the transaction to restore the database to its previous state. In a sense, you are not mocking the Session, because that gets tricky, but you are mocking the actual database.