Moq - How to setup a Lazy interface - c#

I want to mock a Lazy Interface and also Setup a method to return false.
The problem is, when i run the test, I get a NotSupportedException:
System.NotSupportedException: 'Invalid setup on a non-virtual (overridable in VB) member: mock => mock.Value
Here is a simplified example:
[TestMethod]
public void SomeTestMethod()
{
var someService = new Mock<Lazy<IService>>();
/*this line throws the exception*/
someService.Setup(x => x.Value.SomeMethod()).Returns(false);
...
}
Please consider that SomeMethod is actually virtual, but somehow getting the lazy initialization using x.Value is not supported by Moq.
I didn't found a solution for this specific scenario but I did view some other approaches on declarations, but sadly didn't work for me.
[TestMethod]
public void SomeTestMethod()
{
var someService = new Mock<IService>();
var lazySomeService = new Lazy<IService>(() => someService.Object);
//tried this but won't compile
//lazySomeService.Setup(x => x.Value.SomeMethod()).Returns(false);
//lazySomeService.Value.Setup(x => x.SomeMethod()).Returns(false);
...
}

You started on the right track with
var someService = new Mock<IService>();
var lazySomeService = new Lazy<IService>(() => someService.Object);
but the setup needs to be on the mock not the actual Lazy implementation.
someService.Setup(x => x.SomeMethod()).Returns(false);
That way when the Lazy.Value is called, it will be using the mock.

Related

Mocking a Collection ClusterState

I am trying to mock the cluster state of a mongo collection so it gives back a ClusterState.Connected. Below you will see one of my unit tests. Currently this is giving back an error, is there any way to Mock the Collection.Database.Client.Cluster.Description.State?
[Fact]
public void HealthCheck_SucceededDatabase_Connection()
{
//Arrange
var myRepository = new Mock<IRepository<RepoEntityObject>>();
var healthCheck = new HealthCheck(myRepository.Object);
//Setup
myRepository.Setup(mcr => mcr.Collection.Database.Client.Cluster.Description.State).Returns(ClusterState.Connected);
//Act
var result = healthCheck.ExecuteHealthchecks();
//Results
result[0].CheckType.ShouldBe("Service is alive");
result[0].Message.ShouldBe("");
result[0].Passed.ShouldBe(true);
result[1].CheckType.ShouldBe("MongoDB");
result[1].Message.ShouldBe("Service is alive");
result[1].Passed.ShouldBe(True);
}
Error Stack Trace:
System.NotSupportedException occurred HResult=0x80131515
Message=Invalid setup on a non-virtual (overridable in VB) member: mcr
=> mcr.Collection.Database.Client.Cluster.Description.State Source= StackTrace: at
Moq.Mock.ThrowIfSetupExpressionInvolvesUnsupportedMember(Expression
setup, MethodInfo method) at
Moq.Mock.<>c__DisplayClass62_0`2.b__0() at
Test.Unit.HealthCheckTests.HealthCheck_SucceededDatabase_Connection()
in
C:\HealthCheckTests.cs:line
50
Edit One Possible solution:
Making the Description.State attribute virtual is not something I am trying to implement since this method is coming from the MongoDb C# driver that I am using and I am not looking into overriding it.
This is the key phrase Invalid setup on a non-virtual member. Make the property virtual. otherwise if unable to because you are not in control of said property then encapsulate the desired property and expose it as virtual
public interface IRepository<T> {
ClusterState State { get; }
//...other members removed for brevity
}
Now you can mock the member you control
//Arrange
var myRepository = new Mock<IRepository<RepoEntityObject>>();
var healthCheck = new HealthCheck(myRepository.Object);
//Setup
myRepository.Setup(mcr => mcr.State).Returns(ClusterState.Connected);
//...code removed for brevity
Now with that said, you have now realized that your repository is leaking implementation concerns that are difficult to mock in isolation. Consider reviewing your design choices regarding your level of abstractions.

Exception of invocation on the mock was 0 times, but I can see performed invocations correctly

Here's my simplified version of unit test
var service = Fixture.Freeze<IService>();
var outerService = Fixture.Create<OuterService>();
var testObject = Fixture.Create<TestObject>();
outerService.Notify(testObject);
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);
Note that:
outerService.Notify(testObject)
internally calls
IService.SendNotification(string testObject.Name, testObject, extraObject = null)
The above will cause the test to fail, complaining that:
Expected invocation 1 time,but was 0 times:
s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null)
No setups configured.
Performed invocations:
IService.SendNotification("testObject", UnitTest.TestObject, null)
I don't understand, the performed invocation looks exactly like the expected invocation, what is going on here?
EDIT
Ok so it is working if I call service.SendNotification directly in the test, but it won't work if I call it via outerService? Why?
UPDATE
Apologies if my question was not clear enough, here's some more details as to how the Fixture object is configured:
Fixture fixture = new Fixture();
fixture.Customize(new AutoConfiguredMoqCustomization());
fixture.Customize(new SpecimenCustomization());
That is really about it for the details, it's hopefully not a complicated scenario I suppose.
That error occurs when you call Mock.Get and The received mocked instance was not created by Moq. That means that there were No setups configured for the mocked service.
Given this simplified assumption.
public class OuterService {
private IService service;
public OuterService(IService service) {
this.service = service;
}
public void Notify(TestObject testObject) {
service.SendNotification(testObject.Name, testObject, extraObject: null);
}
}
public interface IService {
void SendNotification(string name, TestObject testObject, object extraObject);
}
public class TestObject {
public string Name { get; set; }
}
The following test should work
//Arrange
var service = Mock.Of<IService>();
var outerService = new OuterService(service);
var testObject = new TestObject { Name = "testObject" };
//Act
outerService.Notify(testObject);
//Assert
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);
Moq is now aware of the service object and can extract the mock setup from the mocked instance created above.
Update:
Realized you were using AutoFixture and after some research was able to recreate your problem. You need to customize AutoFixture to use Moq.
Check Auto-Mocking with Moq on how to do that.
The following then worked given the same assumptions stated above.
//Arrange
var fixture = new Fixture();
fixture.Customize(new Ploeh.AutoFixture.AutoMoq.AutoMoqCustomization());
var service = fixture.Freeze<IService>();
var outerService = fixture.Create<OuterService>();
var testObject = fixture.Create<TestObject>();
//Act
outerService.Notify(testObject);
//Assert
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);

Mocking a ViewModel for unit testing with Moq?

New to unit testing. I have a WPF client app hooked into a WCF service via basicHttpbinding. Everything works great. I'm using simple constructor Dependency Injection in my viewModel, passing in an IServiceChannel which I then call me service methods on e.g:
IMyserviceChannel = MyService;
public MyViewModel(IMyServiceChannel myService)
{
this.MyService = myService;
}
Private void GetPerson()
{
var selectedPerson = MyService.GetSelectedPerson();
}
I have then added an MS Test project in the client app and I'm trying to use Moq to mock my service:
[TestMethod]
public void GetArticleBody_Test_Valid()
{
// Create channel mock
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);
// setup the mock to expect the Reverse method to be called
channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
// create string helper and invoke the Reverse method
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
string result = channelMock.GetArticleBody(1010000008);
//Assert.AreEqual("cba", result);
//verify that the method was called on the mock
channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
}
The test is failing with a System.NullReferenceException. Object reference not set to an instance of an object. at the method invocation here:
string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);
so I'm wandering whether this is the best way to approach or am I better somehow mocking an isolated part of the viewModel which is applicable to the test?
The NullReferenceException is mybe thrown because you use MockBehavior.Strict. The documentation says:
Causes this mock to always throw an exception for invocations that don't have a corresponding setup.
Maybe the constructor of ArticleDataGridViewModel calls other methods of the service which you haven't set up.
Another issue is, that you are calling the mocked method directly. Instead you should call a method of your view model, which calls this method.
[TestMethod]
public void GetArticleBody_Test_Valid()
{
// Create channel mock
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>();
// setup the mock to expect the Reverse method to be called
channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
// create string helper and invoke the Reverse method
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
string result = articleDataGridViewModel.MethodThatCallsService();
//Assert.AreEqual("cba", result);
//verify that the method was called on the mock
channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
}
Besides that I think there is no problem with your approach. Maybe the view model violates the single responsibility principle and does more than it should, but that's hard to tell on the basis of your code example.
EDIT: Here's a full example of how you could test something like this:
public interface IMyService
{
int GetData();
}
public class MyViewModel
{
private readonly IMyService myService;
public MyViewModel(IMyService myService)
{
if (myService == null)
{
throw new ArgumentNullException("myService");
}
this.myService = myService;
}
public string ShowSomething()
{
return "Just a test " + this.myService.GetData();
}
}
class TestClass
{
[TestMethod]
public void TestMethod()
{
var serviceMock = new Mock<IMyService>();
var objectUnderTest = new MyViewModel(serviceMock.Object);
serviceMock.Setup(x => x.GetData()).Returns(42);
var result = objectUnderTest.ShowSomething();
Assert.AreEqual("Just a test 42", result);
serviceMock.Verify(c => c.GetData(), Times.Once());
}
}
Without access to your viewmodel, there's only so much help that we can provide you.
However, this code:
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);
...
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
...
string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);
Does not set up your IsesService. If it is not set up in your constructor, that means the IsesService is a null reference. You can't call a method on a null object.
Consider mocking out at a higher level of abstraction then the tight coupling you have with the tool your using.
Perhaps your view-model should rely on services and not a detail of the tool that your using (i.e. IIsesServiceChannel).
Here's an example:
Construct testable business layer logic

Manipulating objects with DbSet<T> and IQueryable<T> with NSubstitute returns error

I'd like to use NSubstitute to unit test Entity Framework 6.x by mocking DbSet. Fortunately, Scott Xu provides a good unit testing library, EntityFramework.Testing.Moq using Moq. So, I modified his code to be suitable for NSubstitute and it's been looking good so far, until I wanted to test DbSet<T>.Add(), DbSet<T>.Remove() methods. Here's my code bits:
public static class NSubstituteDbSetExtensions
{
public static DbSet<TEntity> SetupData<TEntity>(this DbSet<TEntity> dbset, ICollection<TEntity> data = null, Func<object[], TEntity> find = null) where TEntity : class
{
data = data ?? new List<TEntity>();
find = find ?? (o => null);
var query = new InMemoryAsyncQueryable<TEntity>(data.AsQueryable());
((IQueryable<TEntity>)dbset).Provider.Returns(query.Provider);
((IQueryable<TEntity>)dbset).Expression.Returns(query.Expression);
((IQueryable<TEntity>)dbset).ElementType.Returns(query.ElementType);
((IQueryable<TEntity>)dbset).GetEnumerator().Returns(query.GetEnumerator());
#if !NET40
((IDbAsyncEnumerable<TEntity>)dbset).GetAsyncEnumerator().Returns(new InMemoryDbAsyncEnumerator<TEntity>(query.GetEnumerator()));
((IQueryable<TEntity>)dbset).Provider.Returns(query.Provider);
#endif
...
dbset.Remove(Arg.Do<TEntity>(entity =>
{
data.Remove(entity);
dbset.SetupData(data, find);
}));
...
dbset.Add(Arg.Do<TEntity>(entity =>
{
data.Add(entity);
dbset.SetupData(data, find);
});
...
return dbset;
}
}
And I created a test method like:
[TestClass]
public class ManipulationTests
{
[TestMethod]
public void Can_remove_set()
{
var blog = new Blog();
var data = new List<Blog> { blog };
var set = Substitute.For<DbSet<Blog>, IQueryable<Blog>, IDbAsyncEnumerable<Blog>>()
.SetupData(data);
set.Remove(blog);
var result = set.ToList();
Assert.AreEqual(0, result.Count);
}
}
public class Blog
{
...
}
The issue arises when the test method calls set.Remove(blog). It throws an InvalidOperationException with error message of
Collection was modified; enumeration operation may not execute.
This is because the fake data object has been modified when the set.Remove(blog) method is called. However, the original Scott's way using Moq doesn't result in the issue.
Therefore, I wrapped the set.Remove(blog) method with a try ... catch (InvalidOperationException ex) block and let the catch block do nothing, then the test doesn't throw an exception (of course) and does get passed as expected.
I know this is not the solution, but how can I achieve my goal to unit test DbSet<T>.Add() and DbSet<T>.Remove() methods?
What's happening here?
set.Remove(blog); - this calls the previously configured lambda.
data.Remove(entity); - The item is removed from the list.
dbset.SetupData(data, find); - We call SetupData again, to reconfigure the Substitute with the new list.
SetupData runs...
In there, dbSetup.Remove is being called, in order to reconfigure what happens when Remove is called next time.
Okay, we have a problem here. dtSetup.Remove(Arg.Do<T.... doesn't reconfigure anything, it rather adds a behavior to the Substitute's internal list of things that should happen when you call Remove. So we're currently running the previously configured Remove action (1) and at the same time, down the stack, we're adding an action to the list (5). When the stack returns and the iterator looks for the next action to call, the underlying list of mocked actions has changed. Iterators don't like changes.
This leads to the conclusion: We can't modify what a Substitute does while one of its mocked actions is running. If you think about it, nobody who reads your test would assume this to happen, so you shouldn't do this at all.
How can we fix it?
public static DbSet<TEntity> SetupData<TEntity>(
this DbSet<TEntity> dbset,
ICollection<TEntity> data = null,
Func<object[], TEntity> find = null) where TEntity : class
{
data = data ?? new List<TEntity>();
find = find ?? (o => null);
Func<IQueryable<TEntity>> getQuery = () => new InMemoryAsyncQueryable<TEntity>(data.AsQueryable());
((IQueryable<TEntity>) dbset).Provider.Returns(info => getQuery().Provider);
((IQueryable<TEntity>) dbset).Expression.Returns(info => getQuery().Expression);
((IQueryable<TEntity>) dbset).ElementType.Returns(info => getQuery().ElementType);
((IQueryable<TEntity>) dbset).GetEnumerator().Returns(info => getQuery().GetEnumerator());
#if !NET40
((IDbAsyncEnumerable<TEntity>) dbset).GetAsyncEnumerator()
.Returns(info => new InMemoryDbAsyncEnumerator<TEntity>(getQuery().GetEnumerator()));
((IQueryable<TEntity>) dbset).Provider.Returns(info => getQuery().Provider);
#endif
dbset.Remove(Arg.Do<TEntity>(entity => data.Remove(entity)));
dbset.Add(Arg.Do<TEntity>(entity => data.Add(entity)));
return dbset;
}
The getQuery lambda creates a new query. It always uses the captured list data.
All .Returns configuration calls use a lambda. In there, we create a new query instance and delegate our call there.
Remove and Add only modify our captured list. We don't have to reconfigure our Substitute, because every call reevaluates the query using the lambda expressions.
While I really like NSubstitute, I would strongly recommend looking into Effort, the Entity Framework Unit Testing Tool.
You would use it like this:
// DbContext needs additional constructor:
public class MyDbContext : DbContext
{
public MyDbContext(DbConnection connection)
: base(connection, true)
{
}
}
// Usage:
DbConnection connection = Effort.DbConnectionFactory.CreateTransient();
MyDbContext context = new MyDbContext(connection);
And there you have an actual DbContext that you can use with everything that Entity Framework gives you, including migrations, using a fast in-memory-database.

Why does this MustHaveHappened call on a FakeItEasy object fail in MSpec?

When running following test all the assertions fail. Can't figure out why they fail, because the actual implementation does have a call to the objects.
Is this a known bug? Because some other tests do succeed.
[Subject("Pst Cleanup")]
public class When_running_Pst_CleanUp
{
Establish context = () =>
{
_folders = A.Fake<IOutlookFolderParameters>();
_processor = A.Fake<IOutlookPstCleaner>();
};
Because of = () => _processor.Cleanup(_folders);
It should_cleanup_the_mail_folder = () => A.CallTo(() => _folders.EmailFolder).MustHaveHappened();
It should_cleanup_tasks_folder = () => A.CallTo(() => _folders.TaskFolder).MustHaveHappened();
It should_cleanup_appointments_folder = () => A.CallTo(() => _folders.AppointmentFolder).MustHaveHappened();
private static IOutlookPstCleaner _processor;
private static IOutlookFolderParameters _folders;
}
Assertion failed for the following call: Outlook.Contracts.IOutlookFolderParameters.get_NotificationsFolder() Expected to find it at least once but no calls were made to the fake object.
at FakeItEasy.Core.FakeAsserter.AssertWasCalled(Func2 callPredicate, String callDescription, Func2 repeatPredicate, String repeatDescription) at FakeItEasy.Configuration.RuleBuilder.MustHaveHappened(Repeated repeatConstraint) at UnitTests.When_running_Pst_CleanUp.<.ctor>b__2() in When_running_Pst_CleanUp.cs: line 19
This is absolutely correct behavior of FakeItEasy. You need to use the real implementation for IOutlookPstCleaner to make your test succeed. Always make sure that you fake the correct things and don't fake your SUT accidentally.
With testing for the properties just being called you test absolutely nothing valuable. I could as well just write this implementation for IOutlookPstCleanerand your test would succeed:
public class Cleaner : IOutlookPstCleaner
{
public void Cleanup(IOutlookFolderParameters folders)
{
var email = folders.EmailFolder;
var task = folders.TaskFolder;
var appointment = folders.AppointmentFolder;
}
}
If you post your implementation of IOutlookPstCleaner I'm happy to help you find the right things to test.

Categories