I've got a method which takes a IList<Person> and returns an IEnumberable as so:
internal static IEnumerable<Dictionary<string, string>> GetPersonsPerSite(IList<Person> Data)
{
//Implementation ...
}
and I'm trying to create a mock object of IList<Person> so I can test this method.
Using Moq I have written the following:
var mockObjects = new Mock<IList<Person>>();
mockObjects.Setup(x => x[0]).Returns(new Person()
{
SITE_ID = "test",
MPAN = "test",
ADDLINE1 = "test",
ADDLINE2 = "test",
ADDRESS_LINE_1 = "test",
ADDRESS_LINE_2 = "test"
});
However when I come to use the object the IEnumerable returned is aways throwing exception Object reference not set to an instance of an object.
I'm brand new to Moq, and I'm pretty sure I'm missing a fundamental concept here, however I've successfully being able to throw exceptions and modifiy outputs with other mock objects.
I'd appreciate if someone could point me in the right direction.
Don't mock the IList. You don't need to, unless there's something specific your looking to check.
Instead just keep your test simple and do something like this:
var testData = new List<Person>(){new Person()
{
SITE_ID = "test",
MPAN = "test",
ADDLINE1 = "test",
ADDLINE2 = "test",
ADDRESS_LINE_1 = "test",
ADDRESS_LINE_2 = "test"
}};
var result = GetPersonsePerSite(testData);
The code you have got there looks fine and does work for me. Can you expand with an example of where you actually consume the mockObjects.Object and find it null?
Also, do you really need to mock your IList<Person>?
If you are just using it to supply test data to the method under test, just use a concrete list - there is nothing gained by using a mock for this.
Of course, you may be mocking it so you can verify certain actions are taken on it (methods called, properties accessed, etc) - in which case that is different.
Related
I'm writing a unit test which needs to check if two arrays of object match each other. I've tried a few different approaches but all of them fail. The most obvious approach was the CollectionAssert which, according to what I have read, doesn't care about the source only the values and order of the data itself, despite the two array of objects matching each other, the test still fails and I'm lost as to why.
Let's take my unit test
[TestMethod]
public async Task GetMyData_ShouldReturnDataDto_WhenAllIsOk()
{
// Arrange
var userId = "123-456";
Shared.Car customer = new()
{
Id = userId,
OwnerProfile = new Shared.OwnerProfile
{
Title = "Mr",
FirstName = "Bob",
Surname = "Smith",
CarsOwned = new Shared.CarsOwned[]
{
new CarsOwned {
Make = "Ford",
Model = "Mustang",
Rental = false
},
new CarsOwned {
Make = "Ford",
Model = "Fiesta",
Rental = true
}
}
}
};
customerRepo.GetCustomerById(Arg.Any<string>()).Returns(customer);
// Act
var data = await sut.GetCustomerProfile(userId);
// Assert
CollectionAssert.AreEqual(customer.OwnerProfile.CarsOwned, data.CarsOwned);
}
When I set a break point in my test to debug it, I can clearly see that both instances of CarsOwned in the CollectionAssert have identidcal data in the identical order although the sources are different.
Is the CollectionAssert the most appropriate for this setup? I believed it was based on the documentation and the described behaviour.
When I run the test I recieve the error of:
CollectionAssert.AreEqual failed. (Element at index 0 do not match.)
This suggest to me that it's not happy that it's comparing the two arrays from different sources but I could be wrong about that. Any help is appreciated.
I think the issue is that you did not override the Equals() method in the CarsOwned class. I assume that it is this method which is used by CollectionAssert.AreEqual.
By default, the Equals() method return true only if the both parameters have the same reference (~the memory address). It means that in your mind both objects are equals, but for the computer they are completely different objects. So you have to tell to the program how to compare two instance of the same class.
I let you search how implement a correct and efficient Equals() method, but this is not very complicate (because you do not have a lot of field and there is not some complex business logic).
See you, Dylan
I am trying to test an API service using Moq and am getting the error message:
Value cannot be null. (Parameter 'source').
Below is the code [Which is already working fine in the real world, the Mock is a retrospective project.]
models = new List<MyModel> {
new MyModel
{
Id = 1,
Name = "John Smith",
Status = "Engineer",
Centre = 9999
},
new MyModel
{
Id = 2,
Name = "Jane Doe",
Status = "Manager",
Centre = 9999
} };
var mockDbSet = new Mock<DbSet<MyModel>>();
mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(models.AsQueryable().Provider);
mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(models.AsQueryable().Expression);
mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(models.AsQueryable().ElementType);
mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(models.GetEnumerator());
mockDbSet.Setup(m => m.Add(It.IsAny<MyModel>())).Callback<MyModel>(models.Add);
mockContext = new Mock<LiveDbContext>();
mockContext.Setup(m => m.Add(models)).Callback<DbSet<MyModel>>(mockDbSet.Object.AddRange);
myService = new LiveService(mockContext.Object);
var result = myService.GetStaffByCentre(9999).Result.ToList();
//Assert
Assert.AreEqual(1, result.Count);
The line that appears to be causing the error is the
var result = myService.GetStaffByCentre(9999).Result.ToList();
Just to give an update, and perhaps help others in the same situation. I realised that I needed to add a Repository layer and create a mock of it in order to create and run Unit Tests.
The Mock repository used the 'models' list [see original post] as its data source which meant I could remove the need to create a 'Mock Context' object and a mock DbSet.
I found this tutorial very helpful.
We don't really know what your service/SUT is doing because you haven't provided it, but I assume it performs a query on the DbSet<MyModel> and returns the unresolved enumerable as the Result member. If that is the case, the ToList() invocation is where the exception will be occurring, when the enumerable is resolved.
Before we go further, my first question would be can you use the in-memory database provider. Mocking EFCore is hard and Microsoft doesn't recommend it.
If there is a reason you can't use the in-memory database provider, and my assumptions are correct, this is probably occurring because you haven't set up the query provider methods such as CreateQuery and Execute which are used by LINQ extensions. Exactly which you need to mock again I can't say, I don't have enough detail.
I have a method that I´m trying to mock using NSubstitute:
Foo MyMethod(IEnumerable<string> args);
I want the method to return new Foo { ID = 1 } for a call where the args-collection has exactly one item called "Item1". However when the collection contains only "Item2" I´d like to return another instance of Foo.
So I wrote this code:
var mock = Substitute.For<MyType>();
mock.MyMethod(new[] { "Item1" }).Returns(new Foo { ID = 1 });
mock.MyMethod(new[] { "Item2" }).Returns(new Foo { ID = 2 });
In my calling code I have something like this:
var foo = myType.MyMethod(new[] { "Item1" });
However the mock isn´t executed as arrays are compared using reference-equality. So as I have two instances of string[] sharing the same values they are considered unequal and thus we don´t jump to the mocked return-statement.
So what I´d like to achieve is no matter what exact type of collection we provide to the method the mock should just distinguish on the collections items.
You can use the Arg.Is syntax to do the check yourself:
mock.MyMethod(Arg.Is<string[]>(a => a.Contains("Item1"))).Returns(new Foo { ID = 1 });
mock.MyMethod(Arg.Is<string[]>(a => a.Contains("Item2"))).Returns(new Foo { ID = 2 });
See here for more information: http://nsubstitute.github.io/help/return-for-args/
I am trying to understand the DynamicDictionary in NancyFX, it looks pretty cool. Does anyone know of a blog post or similar, that goes through the internals of it?
I need a propertybag to pass around objects, that I don't know the content of because they come from outside my system as JSON. But based on the contents of these objects, such as the presence of certain properties I need to do stuff.
I could just pass around dynamic objects, but that is a bit too vague I think. Don't really like that.
I would need nested dictionaries, to fully represent the object graph.
The dynamic dictionary is just a ExpandoObject with a Dictionary in it. So it can still be accessed like a dictionary.
For example, in MVC you access Form properties like so:
var name = Request["name"];
or
var name = Request.Form["name"];
When a request comes into Nancy you can access it via the dot notation. Or via the class indexer.
var name = parameters.name;
var name = parameters["name"];
This is handy when you're sending query string or form names that have values that cannot be used in dot notation.
var firstName = parameters["first-name"];
The values are also dynamic, so it could be made up of nested objects. This allows you to do stuff like:
var firstName = parameters.contact.firstname;
So if you're passing a JSON payload to the request then you can access the entire structure using dot notation.
However you will probably find most developers using Nancy only ever access Route values or QueryString values using this method.
Get["/products/{id:int}/"] = parameters => {
int id = parameters.id;
};
So back to the original question:
Is there a blog post or any doco: Nope.
Why does it exist: For sugar syntax.
Can I use it for what I want: Yes absolutely!
Can you tell me how to use it: Nope, however it shouldn't be hard. Just look the model binding in Nancy to figure it out. It's not too hard.
Just an edit based on the answer by the OP.
When you access the dot notation, continued dot notation will only work on further dynamic types.
This means using var will cause an exception because of the way var and dynamic are handled by the compiler.
When you do:
var person = parameters.person;
var name = person.name;
parameters is currently dynamic and implements TryGetMember, this internally looks up a dictionary of values and attempts to return the value.
When you define the object as var for the person variable. The compiler assumes that anything after that exists on the object, so it looks for name on the person variable.
Since name does not exist as a member of person it will throw.
To resolve this, the variable must be assigned as dynamic. So the example becomes:
dynamic person = parameters.person;
var name = person.name;
This will work.
So I started working with the DynamicDictionary and it is pretty cool and easy to work with. Only one thing bugs me right now. That is if I nest DynamicDictionaries.
Look at the following example:
private void TestNestedDynamicDictionary()
{
dynamic dictionary = new DynamicDictionary();
dynamic nestedDictionary = new DynamicDictionary();
nestedDictionary.Add("name", "Peter");
dictionary.Add("person", nestedDictionary);
var person = dictionary.person;
var name = person.name;
Console.WriteLine(name);
}
This fails when trying to access person.name with a 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
DynamicDictionaryValue' does not contain a definition for 'name'
If I just do an explicit cast like this it works.
var person = (DynamicDictionary)dictionary.person;
Any input on how I could make it behave as DynamicDictionary right out of the box... apart from checking the DynamicDictionaryValue before it is returned, and do the cast there, which I think is messy.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
object value;
if (!dictionary.TryGetValue(binder.Name, out value))
{
result = new DynamicDictionaryValue(null);
return true;
}
var dictVal = value as DynamicDictionaryValue;
if (null != dictVal && dictVal.Value is DynamicDictionary)
{
result = dictVal.Value;
}
else
{
result = value;
}
return true;
}
I've been looking at the Moq documentation and the comments are too short for me to understand each of things it can do.
The first thing I don't get is It.IsAny<string>(). //example using string
Is there an advantage of using this over just putting some value in? I know people say to use this if you don't care about the value, but if you don't care about the value can't you just do "a" or something? This just seems like more typing.
Secondly, when would be an example be of when you would not care about the value? I thought Moq needs the value to match up stuff.
I don't get what It.Is<> is for at all or how to use it. I don't understand the example and what it is trying to show.
Next, I don't get when to use Times (and its AtMost methods and similar). Why would you limit the number of times something is set up? I have some AppConfig value that I need to use twice. Why would I want to limit it to, say, once? This would just make the test fail. Is this to stop other people from adding another one to your code or something?
I don't get how to use mock.SetupAllProperties();
What does it set up the properties with?
I don't also get why there are so many different ways to set up a property and what their differences are. The documentation has:
SetupGet(of property)
SetupGet<TProperty>
I noticed that a lot of the stuff in Moq shows () and <> - what's the difference between them and what would they look like in use?
I also don't get why they have SetupGet. Would you not use SetupSet to set a property?
SetupSet has five different ways to use it in the documentation. Plus another one called SetupProperty. So I don't understand why there are so many.
On a side note, I am wondering if variables used in lambdas are independent of other lambdas. E.g.:
mock.setup(m => m.Test);
stop.setup(m => m.Test);
Would this be ok or would there be some conflict between the variable m?
Finally, I was watching this video and I am wondering if it shows Visual Studio. His Intellisense looks different. A lightbulb pops up for him (I am happy mine does not, as it brings back painful memories of netbeans), and there are lines going from one opening brace to the closing brace and etc.
It.IsAny / It.Is
These can be useful when you're passing a new reference type within the code under test. For instance, if you had a method along the lines of:
public void CreatePerson(string name, int age) {
Person person = new Person(name, age);
_personRepository.Add(person);
}
You might want to check the add method has been called on the repository,
[Test]
public void Create_Person_Calls_Add_On_Repository () {
Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
PersonManager manager = new PersonManager(mockRepository.Object);
manager.CreatePerson("Bob", 12);
mockRepository.Verify(p => p.Add(It.IsAny<Person>()));
}
If you wanted to make this test more explicit you can use It.Is by supplying a predicate the person object must match,
[Test]
public void Create_Person_Calls_Add_On_Repository () {
Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
PersonManager manager = new PersonManager(mockRepository.Object);
manager.CreatePerson("Bob", 12);
mockRepository.Verify(pr => pr.Add(It.Is<Person>(p => p.Age == 12)));
}
This way the test will through an exception if the person object that was used to call the add method didn't have the age property set to 12.
Times
If you had a method along the lines of:-
public void PayPensionContribution(Person person) {
if (person.Age > 65 || person.Age < 18) return;
//Do some complex logic
_pensionService.Pay(500M);
}
One of the things that you might want to test is that the pay method does not get called when a person aged over 65 is passed into the method
[Test]
public void Someone_over_65_does_not_pay_a_pension_contribution() {
Mock<IPensionService> mockPensionService = new Mock<IPensionService>();
Person p = new Person("test", 66);
PensionCalculator calc = new PensionCalculator(mockPensionService.Object);
calc.PayPensionContribution(p);
mockPensionService.Verify(ps => ps.Pay(It.IsAny<decimal>()), Times.Never());
}
Similarly, it's possible to imagine situations where you're iterating over a collection and calling a method for each item in the collection and you'd like to make sure that it's been called a certain amount of times, other times you simply don't care.
SetupGet / SetupSet
What you need to be aware of with these guys is that they reflect how your code is interacting with the mock rather than how you're setting up the mock
public static void SetAuditProperties(IAuditable auditable) {
auditable.ModifiedBy = Thread.CurrentPrincipal.Identity.Name;
}
In this case, the code is setting the ModifiedBy property of the IAuditable instance while it's getting the Name property of the current instance of IPrincipal,
[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
Mock<IAuditable> mockAuditable = new Mock<IAuditable>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");
Thread.CurrentPrincipal = mockPrincipal.Object;
AuditManager.SetAuditProperties(mockAuditable.Object);
mockPrincipal.VerifyGet(p => p.Identity.Name);
mockAuditable.VerifySet(a => a.ModifiedBy = "test");
}
In this case, we're setting up the name property on the mock of IPrincipal so it returns "test" when the getter is called on the Name property of Identity we're not setting the property itself.
SetupProperty / SetupAllProperties
Looking at the test above if it was changed to read
[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
Mock<IAuditable> mockAuditable = new Mock<IAuditable>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");
var auditable = mockAuditable.Object;
Thread.CurrentPrincipal = mockPrincipal.Object;
AuditManager.SetAuditProperties(auditable);
Assert.AreEqual("test", auditable.ModifiedBy);
}
The test would fail. This is because the proxy created by Moq doesn't actually do anything in the set method of a property unless you tell it to. In effect, the mock object looks a bit like this
public class AuditableMock : IAuditable {
public string ModifiedBy { get { return null; } set { } }
}
To get the test to pass you have to tell Moq to set up the property to have the standard property behavior. You can do this by calling SetupProperty and the mock will look more like
public class AuditableMock : IAuditable {
public string ModifiedBy { get; set; }
}
and the test above would pass as the value "test" would now get stored against the mock. When mocking complex objects you might want to do this for all properties, hence the SetupAllProperties shortcut
Finally, the lightbulb in the IDE is the ReSharper plugin.
If you don't care about the exact value of a property, it's far better to use .IsAny because you are being explicit about the fact that the exact value is not important. If you hardcode it as "abc", then it is not clear if your code you are testing depends on starting with "a" or ending with "c" or being 3 chars long, etc. etc.