I have a method that accepts an IEnumerable:
MyMethod(IEnumerable<MyClass> myParameter)
Now I am writing this code to mock the service:
var array1 = new MyClass[0];
var array2 = new MyClass[0];
_service
.Setup(s => s.MyMethod(array1))
.Returns(value1);
_service
.Setup(s => s.MyMethod(array2))
.Returns(value2);
And finally I am doing two calls to the service with both arrays inside system under test:
_service.MyMethod(array1);
_service.MyMethod(array2);
What I do expect is to get value1 and value2 from these calls, but in practice the latter call overrides the first one and I only get value2 from both calls.
Is this a bug in Moq or is this a feature that setup treats IEnumerable not as a separate object but rather tries to expand it and compare all elements or something (resulting in two empty arrays being the same setup call)?
When you create multiple setups on a method with Moq, each subsequent setup will replace the previous setup unless the setups are conditional (they specify certain conditions on the arguments). See this answer.
You can fix your code by specifying that the arguments must match the ones you intend to pass:
[Test]
public void MyTest()
{
var service = new Mock<MyClass>();
var array1 = new MyClass[0];
var array2 = new MyClass[0];
var value1 = "value1";
var value2 = "value2";
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1))).Returns(value1);
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2))).Returns(value2);
Assert.AreEqual(value1, service.Object.MyMethod(array1));
Assert.AreEqual(value2, service.Object.MyMethod(array2));
}
The behaviour you describe is the default behaviour of the moq, you can see it here. It indeed unfold enumerable and invoke IEnumerable.SequenceEqual. However that is default behaviour(if you setup using an instance, Constant matcher) and you could override it. The one approach is what Owen suggested to use It.Is<T> matcher, e.g.
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1)))
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2)))
Notice that == by default do ReferenceEquals() so this will make different non overridable setups.
Related
I have a test where I have a set of parameters, and I'd like to verify that the method was called and each parameter was specified exactly once. I can do this:
var paramList = new List<string> { "one", "two", "three", "four" };
paramList.ForEach(x => MyMock.Verify(y => y.DoSomething(x), Times.Once));
But I'm wondering if Moq offers something I can do with just a single Verify call.
I don't think moq offers that if I am not mistaken. The problem is that even if you have proper setup with Verifiable to use Verify or if you want to use VerifyAll you cannot specify Times limitation.
Verify
paramList.ForEach(s => mock.Setup(m => m.DoSomething(s)).Verifiable());
mock.Object.DoSomething("one");
mock.Object.DoSomething("two");
mock.Object.DoSomething("three");
mock.Object.DoSomething("four");
mock.Verify(); //Cannot specify Times
VerifyAll
paramList.ForEach(s => mock.Setup(m => m.DoSomething(s)));
mock.Object.DoSomething("one");
mock.Object.DoSomething("two");
mock.Object.DoSomething("three");
mock.Object.DoSomething("four");
mock.VerifyAll(); //Cannot specify Times
Although, I do not see any problem with your approach I just want to add one more option. You could avoid Verify by using Capture.In feature, something like this:
//Arrange
var invocation = new List<string>();
mock.Setup(m => m.DoSomething(Capture.In(invocation)));
//Act
mock.Object.DoSomething("one");
mock.Object.DoSomething("two");
mock.Object.DoSomething("three");
mock.Object.DoSomething("four");
//Assert
CollectionAssert.AreEquivalent(paramList, invocation);
I mocked FindAsync by the following code:
var brands = new Mock<DbSet<Brand>>();
ConfigureTheDbSet(brands, brandData);
brands.Setup(b => b.FindAsync(It.IsAny<object[]>())) //substitution of the .SelectAsync(id) method
.Returns<object[]>(ids => brands.Object.FirstOrDefaultAsync(b => b.BrandId == (int) ids[0]));
and it had been working correctly until I added mocking for AsNoTracking to context:
var mockContext = new Mock<ReportDbContext>();
mockContext.Setup(m => m.Set<Brand>()).Returns(brands.Object);
mockContext.Setup(m => m.Set<Brand>().AsNoTracking()).Returns(brands.Object);
And FindAsync returns null. To make it work i added the following mocking:
mockContext.Setup(m => m.Set<Brand>().FindAsync(It.IsAny<object[]>()))
.Returns<object[]>(async d => await brands.Object.FindAsync(d));
Anybody have a clue why this is happening?
IMO, you should be mocking interfaces, for example IBrandRepository. Otherwise whats the point of mocking? - you could just create an instance of your class, call FindAsync() and assert the result as usual..
Here is how I use Moq with interfaces, for example a repo interface;
// arrange
var mockRepo = new Mock<IBrandRepository>();
mockRepo.Setup(o => o.FindAsync(It.IsAny<string>())).ReturnsAsync(new Brand[] { ... });
var someClass = new SomeClass(IBrandRepository); // someClass that use IBrandRepository
// act
string search = "brand1 brand2"; // what the user searches for
var results = someClass.FindBrands(searchText) // internally calls IBrandRepository.FindAsync()
// assert
// Assert.AreEqual(results.Count(), ...
Dimitry, I know that it's been a couple of years. I just had the same issue and this is what I did to get it to work
this.mocContext.Setup(x => x.Company.FindAsync(It.IsAny<string>
())).Returns(Task.FromResult(this.GetCompanyList().SingleOrDefault(x =>
x.CompanyCode.Equals("M5QoKF4AS0"))));
Here mocContext is my Moq'd Database, Company is the table that I want to perform the FindAsync on, the Get CompanyList just pulls from the data the populated the table. Hopefully this helps
I circumvented this mocking by using .Where(entity => entity.PrimaryKey == key).FirstOrDefaultAsync() in place of .FindAsync(key) as FirstOrDefaultAsync did not require a separate mocking and logic is also same between both approaches
For anyone struggling with this, here's another way of doing it:
First: Create a mock of the DbContext and the DbSet, ex:
private static readonly Mock<ApplicationDbContext> mockDbContext = new();
private static readonly Mock<DbSet<Game>> mockGameSet = new();
Second: Setup the Get of the DbSet in the Mocked DbContext, like this:
mockDbContext.SetupGet(_ => _.Games).Returns(mockGameSet.Object);
Third, and Last: Setup the FindAsync() in the mocked DbSet like this:
mockGameSet.Setup(x => x.FindAsync(It.IsAny<int>())).ReturnsAsync(game);
I'm using Moq to write unit tests that use Entity Framework 6 DbSet and DbContext objects. I have a service method with a cascading/multi-level Include and I can't figure out how to set it up for testing. The service method looks something like this:
return DataContext.Cars
.Include(p => p.Model)
.Include(p => p.Model.Make)
.Select(c => new
{
Key = c.CarId,
Value = string.Format("{0} {1} {2}", c.Model.Make.Name, c.Model.Name, c.Trim)
}
).ToArray();
I know that I have to setup the Include to return the mocked object, like this:
mockCarDbSet.Setup(m => m.Include(It.IsAny<string>())).Returns(mockCarSet.Object);
But I'm getting a null reference exception from the cascaded .Include(p => p.Model.Make). How do I set up Moq to handle multiple levels of Include?
EDIT
OK, so it turns out that I can't use It.IsAny<string> for Include calls that use lambdas instead of strings, so now I have two problems:
How do I setup a mock with Include that accepts a lambda?
Will the setup for above cascade to multiple levels?
include() is a static method(extension method).
Moq doesn't support a static methods mock(read this link).
To test your code you need to set your mockCarDbSet to return IQueryable<Car>:
var carQuery = new List<Car>
{
//add cars
}
IQueryable<Post> query = carQuery.AsQueryable();
return query as a result of DataContext.Cars
Those steps will work around the static method problem.
So thanks to #Old Fox reminding me that Moq won't work with static members, I found a way to do this using Microsoft Fakes. Shims allows you to shim static methods. I used Moq to set up Mock<DbSet> objects for each of the entities:
var carData = new List<Car>{new Car{ Trim = "Whatever" }};
var mockCarSet = new Mock<DbSet<Car>>();
mockCarSet.As<IQueryable<Car>>().Setup(m => m.Provider).Returns(carData.Provider);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.Expression).Returns(carData.Expression);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.ElementType).Returns(carData.ElementType);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.GetEnumerator()).Returns(carData.GetEnumerator);
var mockMakeSet = new Mock<DbSet<Make>>();
//do the same stuff as with Car for IQueryable Setup
var mockModelSet = new Mock<DbSet<Model>>();
//do the same stuff as with Car for IQueryable Setup
using(ShimsContext.Create())
{
//hack to return the first, since this is all mock data anyway
ShimModel.AllInstances.MakeGet = model => mockMakeSet.Object.First();
ShimCar.AllInstances.ModelGet = car => mockModelSet.Object.First();
//run the test
}
Is there a way of asserting that no methods were called in MockRepository?
Say I have:
var repo = MockRepository.GenerateStub<RealRepo>();
I know I can do:
repo.AssertWasNotCalled(...);
But is there a way of checking that it was not used? Instead of doing all the methods everytime i want to check if a repo was not used?
I have cases where I want to just check that I don't use this repo.
Use StrictMock instead of stub:
var repo = MockRepository.GenerateStrictMock<RealRepo>();
It will throw exception if you will try to call any member which do not have setup.
BTW same is true for Moq:
var repoMock = new Mock<RealRepo>(MockBehavior.Strict);
You can try adding your own extension to Rhino Mocks. Something like this:
public static void AssertNothingWasCalled<T>(this T mock)
{
var methodsToVerify = typeof (T)
.GetMethods()
.Where(m => !m.IsSpecialName);
foreach (var method in methodsToVerify)
{
var arguments = BuildArguments(method);
var action = new Action<T>(x => method.Invoke(x, arguments));
mock.AssertWasNotCalled(action, y => y.IgnoreArguments());
}
}
private static object[] BuildArguments(MethodInfo methodInfo)
{
return methodInfo
.GetParameters()
.Select(p => Arg<object>.Is.Anything)
.ToArray();
}
But the answer by Sergey Berezovskiy seems a bit simpler.
Perhaps the easiest thing to do would be to pass a null ref to the calling class. Your SUT should throw a NullReferenceException if it attempts to use it. This is possibly the simplest thing that will work.
However, if the SUT checks for null, then this won't work.
I would like to unit test an Add method in a repository that returns void. I'm interested in testing the actual adding of elements without hitting the database (not whether Add was called or not). Is this the correct way?
var list = new List<Foo>();
var repo = new Mock<IFooRepository>();
repo.Setup(x => x.Add(It.IsAny<Foo>()))
.Callback((Foo f) =>
{
list.Add(f);
});
repo.Object.Add(new Foo { FooId = 1 });
Assert.IsTrue(list.Any(x => x.FooId == 1));
No, the only thing you're testing here is Moq itself. You could try mocking the underlying layer, e.g. ISession if you're using Nhibernate.