Rhino Mocks, assert that a MockRepository was not used (methods)? - c#

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.

Related

Moq setup treats all empty enumerables/arrays as the same parameter

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.

Mock extension methods IElasticClient

Is there a way to mock the following
var result = await Client.SearchAsync<IndexedSite>(d => d
.Index(SiteIndexName)
.Query(q => q.MatchAll())
.Sort(sd => sd.Field(s => s.Name, SortOrder.Ascending))
.Take(c_maxSiteListSize));
Would one use .Callbacks in this situation?
My current setup:
private Mock<IElasticClient> _client = new Mock<IElasticClient>();
private Mock<ISearchResponse<IndexedSite>> indexedSite = new Mock<ISearchResponse<IndexedSite>>();
_client.Setup(x =>
x.SearchAsync<IndexedSite>(It.IsAny<Func<SearchDescriptor<IndexedSite>, ISearchRequest>>(),
default(CancellationToken))).Returns(Task.FromResult(indexedSite.Object));
This works, and it does return indexedSite, however it does not 'Cover' .Index/.Query/.Sort/.Take extension methods, which is what I want.
Per #Olegl answer. It is not possible to Mock extension methods. You need to refactor and get rid of extension methods in order to make it testable
More info here

Mocking FindAsync method

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);

When unit testing, how do I mock a return null from async method?

Normally, I mock my repo like so:
var repository = new Mock<ISRepository>();
repository.Setup(r => r.GetMemberAsync(email))
.Returns(Task.FromResult(new Member
{
FirstName = firstName,
LastName = lastName
}));
But, in my code, I check to see if the member is not found, i.e. GetMemberAsync returns null. How do I mock this?
I tried:
var repository = new Mock<ISRepository>();
repository.Setup(r => r.GetMemberAsync(email))
.Returns(Task.FromResult<object>(null));
but I get a compile error.
You get a compiler error because you return a task that doesn't match the type the async method returns. You should return Task<Member> instead of simply Task<object>:
repository.Setup(r => r.GetMemberAsync(email)).Returns(Task.FromResult<Member>(null));
It is also possible to return the result without using the Task class.
repository
.Setup(r => r.GetMemberAsync(email))
.ReturnsAsync((Member)null);
Old question but you can also do this which I think it cleaner:
Assuming the default value of your object is null you can also use:
default(<insert object type here>)
e.g.
default(Member)
default(List<string>)
etc.
Full Example:
var myRepo = new Mock<IMyRepo>();
myRepo
.Setup(p => p.GetAsync("name"))
.ReturnsAsync(default(List<string>));

How to find an overloaded method by reflection

This is a question associated with another question I asked before. I have an overloaded method:
public void Add<T>(SomeType<T> some) { }
public void Add<T>(AnotherType<T> another) { }
How can I find each method by reflection? e.g. How can I get the Add<T>(SomeType<T> some) method by reflection? Can you help me please? Thanks in advance.
The trick here is describing that you want the parameter to be SomeType<T>, where T is the generic type of the Add method.
Other than that, it's just about using standard reflection, like CastroXXL suggested in his answer.
Here's how I did it:
var theMethodISeek = typeof(MyClass).GetMethods()
.Where(m => m.Name == "Add" && m.IsGenericMethodDefinition)
.Where(m =>
{
// the generic T type
var typeT = m.GetGenericArguments()[0];
// SomeType<T>
var someTypeOfT =
typeof(SomeType<>).MakeGenericType(new[] { typeT });
return m.GetParameters().First().ParameterType == someTypeOfT;
})
.First();
Look into the MethodInfo Members: http://msdn.microsoft.com/en-US/library/system.reflection.methodinfo_members(v=vs.80).aspx
There are helper properties for IsGenericMethodDefinition and GetParameters. Both could help you figure out what function is what.

Categories