Unit testing a method with Moq - c#

I'm trying to learn how to do Unit testing with C# and Moq, and I've built a little test situation. Given this code:
public interface IUser
{
int CalculateAge();
DateTime DateOfBirth { get; set; }
string Name { get; set; }
}
public class User : IUser
{
public DateTime DateOfBirth { get; set; }
string Name { get; set; }
public int CalculateAge()
{
return DateTime.Now.Year - DateOfBirth.Year;
}
}
I want to test the method CalculateAge(). To do this, I thought I should try giving a default value to the DateOfBirth property by doing this in my test method:
var userMock = new Mock<IUser>();
userMock.SetupProperty(u => u.DateOfBirth, new DateTime(1990, 3, 25)); //Is this supposed to give a default value for the property DateOfBirth ?
Assert.AreEqual(22, userMock.Object.CalculateAge());
But when It comes to the assertion, the value of CalculateAge() equals 0, although DateOfBirth equals new DateTime(1990, 3, 25).
I know this may look like a silly example, but whatever... I thought I could use mocking to give values to not-yet-developed method/properties in my objects, so the testing of a method wouldn't depend on another component of my class, or even setting up a default context for my object (hence the name of the user here...) Am I approaching this problem the wrong way?
Thanks.

Yes, you approaching it wrong, but don't worry, I'll explain why. First hint would be
you can completely remove your User class and everything will be the
same.
When you are doing:
var userMock = new Mock<IUser>();
You just creating a fake\mock object of that interface, that has nothing to do with your initial User class, so it doesn't have any implementation of CalculateAge method, except of fake one that just silly returns 0. That's why you are getting 0 in your assert statement.
So, you were saying:
thought I could use mocking to give values to not-yet-developed
method/properties in my objects, so the testing of a method wouldn't
depend on another component of my class
You could, let's say you will have some consumer of your IUser, lets say like the following:
class ConsumerOfIUser
{
public int Consume(IUser user)
{
return user.CalculateAge() + 10;
}
}
in that case mocking of IUser will make total sense, since you want to test how your ConsumerOfIUser behaves when IUser.CalculateAge() returns 10. You would do the following:
var userMock = new Mock<IUser>();
userMock.Setup(u => u.CalculateAge()).Returns(10);
var consumer = new ConsumerOfIUser();
var result = consumer.Consume(userMock);
Assert.AreEqual(result, 20); //should be true

It depends on what your trying to test. In this case, you have mocked out the User object, so there is no point in testing anything inside this class as you are replacing it with a mock object. If you want to test the User object then you shouldn't mock it out.
Mocks are used to replace dependant objects that you don't want to test. For example, if you had a Name object instead of a string (e.g contains first name, surname, title etc..) but you didn't want to test the Name object, just the User object, you would create a mock of the Name object to be used when constructing the User object.

Related

Mocking a method to assign value to field in Model C# Moq

I need to add a method to a model that given some parameters assigns a value to one of the model's fields.
public class ModelName: SomeModel<ModelName>, IModelName
{
[Field]
public string SomeField{ get; set; }
[Field]
public string FieldSetByMethod{ get; set; }
public new async Task MethodToSetField(string parameter)
{
var someClassInstance = new SomeExternalClass(parameter);
FieldSetByMethod = someClassInstance(parameter).method();
}
}
Now when I'm writing unit tests and I want to have a way of checking that this MethodToSetField was called. However, I can't really actually call the MethodToSetField method as creating SomeExternalClass is not desirable (e.g. because it creates unique ID).
I don't really have experience with neither C# nor Moq. How can I mock this function so it behaves more or less like this:
ModelNameInstance.Setup(c => c.MethodToSetField("Parameter")).Assigns(FieldSetByMethod,"DummyValue");
Or maybe I can somehow restructure the code / write tests in a way to imitate this behavior?
You could inject ISomeExternalClass into this class and then mock it, and test against the mock, or if you can't do that - inject ISomeExternalClassFactory into this class and then mock it. ISomeExternalClassFactory mock would return a mock of ISomeExternalClass that you could setup and test against.

Unit Test for two classes inherit an Interface

I have two classes that implement an interface, but both classes have a parameter passed into the constructor to identify what class the application would need. I am trying to test one (GetAvailablity) method on (AvailablityRepoData) class when I create an instance of AvailablityRepoData I am getting an error for non-virtual method. I would really appreciate if someone can point me to the right direction.
public interface IAvailablityRepo
{
string GetAvailablity(Availablity availablity);
}
public class AvailablityRepoData: IAvailablityRepo
{
public AvailablityRepoData(string websetting) {
}
public string GetAvailablity(Availablity availablity) {
return "Data";
}
}
public class AvailablityRepoWeb:IAvailablityRepo
{
public AvailablityRepoWeb(string DataSetting) {
}
public string GetAvailablity(Availablity availablity) {
return "Web";
}
}
public class Availablity
{
public virtual string Id {
get;
set;
}
public virtual string Status {
get;
set;
}
}
var a = new Availablity() { Id = "111", Status = "A"};
Mock<IAvailablityRepo> mockRepo = new Mock<IAvailablityRepo>();
Mock<IAvailablityRepo> RepoData = new Mock<IAvailablityRepo>();
RepoData.Setup(x => x.GetAvailablity(It.IsAny<Availablity> ())).Returns("pass");
var result = RepoData.Object.GetAvailablity(a);
As has already been said in the comments, it's not clear from the code you've posted what your error is. If I copy and past it straight into visual studio (wrapping the test code in a test), the test passes fine. I'm going to suggest that when you experienced the error, you test code was actually closer to this:
[TestMethod]
public void TestMethod1() {
var a = new Availablity() { Id = "111", Status = "A" };
Mock<IAvailablityRepo> mockRepo = new Mock<IAvailablityRepo>();
Mock<AvailablityRepoData> RepoData = new Mock<AvailablityRepoData>();
RepoData.Setup(x => x.GetAvailablity(It.IsAny<Availablity>())).Returns("pass");
var result = RepoData.Object.GetAvailablity(a);
}
This results in an error when the test is run:
System.NotSupportedException:Invalid setup on a non-virtual (overridable in VB) member:
x => x.GetAvailablity(It.IsAny<Availablity>())
The difference between this test and your original test is that I've changed the Mocked type from the interface IAvailabilityRepo to AvailabilityRepoData which is the concrete class. Since Moq only supports mocking of interfaces / virtual methods it's naturally getting upset.
As has been mentioned by #prgmtc, your test as it stands doesn't really testing much of anything.
With your current code, it doesn't actually look like you need to be using Mocks at all. Something like this might be a more appropriate test:
[TestMethod]
public void TestDataRepoReturnsDataAvailability() {
var someImportantSetting = "thisShouldBeSomethingMeaningful";
var availability = new Availablity() { Id = "111", Status = "A" };
var sut = new AvailablityRepoData(someImportantSetting);
var returnedAvailability = sut.GetAvailablity(availability);
Assert.AreEqual("Data", returnedAvailability);
}
Assuming your actual code is more complex the string passed into your data repo would presumably need to be rather more meaningful...
As a general rule of thumb, you shouldn't be mocking the system under test. If you find yourself creating a mock for the system you're testing it's a good indication that you've got to much functionality in one class and/or you're trying to test the wrong thing...
As an asside, you may want to look into something like the builder pattern to create your different repos rather than passing the type into the constructor for each of the repos as you seem to be suggesting.

How to mock a Class with IEnumerable

I am using Moq for unit testing in C# and want to put some fake data in the following class.
public class UserResponse
{
public IEnumerable<usertab> userlist{get;set;}
public string Name {get;set;}
public string state {get;set;}
public string country {get;set}
}
public class usertab
{
public string tname {get;set;}
public string fname {get;set;}
}
Please correct me if below code is correct to fake a class wtih IEnumerable
var userdata = new usertab[]{
new usertab{tName="Employee",fName="abc"},
new usertab{tName="Employee",fName="xyz"},
};
Well you're not "faking" it at all - you're just using an array as the implementation. There's nothing wrong with doing that - personally I like using real code within tests, so long as:
You have confidence in the other code you're relying on (arrays in this case) either because it's supplied from a trustworthy source (the BCL in this case) or you have tests
You don't need to perform interaction testing - for example, if you want to check that you only iterate over the collection once, arrays won't help you do that
The real code doesn't slow down the testing (e.g. by making network connections, requiring a database etc). Not a problem with arrays.

Frozen mock's property is getting overwritten

I'm having an issue where AutoFixture seems to be overwriting a property on a frozen mock. The property on the mocked class is read-only, and from what I've read, AutoFixture shouldn't be trying to do anything with it.
I've included code to reproduce the issue in LINQPad below. Victim is a trivial test class with two read-only properties. At issue is that once I have set the expectation for the Things property and registered the mock's Object as the instance for AutoFixture to return for the Victim type, the collection Things contains different strings.
To reproduce the problem, run the code below in LINQPad as a C# Program and reference AutoFixture and Moq from NuGet. Be sure to include the namespaces Moq and Ploeh.AutoFixture.
My expectation is that I should get back the object I registered with Register and that the collection Things in the returned Victim should return the collection I referenced in my call to SetupGet.
public class Victim
{
private string _vic;
private IEnumerable<string> _things;
public virtual string VictimName { get { return _vic; } }
public virtual IEnumerable<string> Things { get { return _things; } }
}
void Main()
{
var fixture = new Fixture();
var victimName = fixture.CreateAnonymous("VIC_");
var things = fixture.CreateMany<string>();
victimName.Dump("Generated vic name");
things.Dump("Generated things");
var victimMock = fixture.Freeze<Mock<Victim>>();
victimMock.SetupGet(x => x.VictimName).Returns(victimName).Verifiable();
victimMock.SetupGet(x => x.Things).Returns(things).Verifiable();
fixture.Register(() => victimMock.Object);
var victim = fixture.CreateAnonymous<Victim>();
(victim.Equals(victimMock.Object)).Dump("Victims are the same?");
victim.VictimName.Dump("Returned name");
victim.Things.Dump("Returned things");
(things.Equals(victim.Things)).Dump("Returned things are the same?");
victimMock.Verify();
}
My guess is that the Iterator for Things is actually the same, but that the strings it generates are different. This is actually by design, although we've later come to realize that this wasn't a particularly good design decision.
In AutoFixture 3, this behavior has been changed.
If I've guessed correctly, this issue will go away in AutoFixture 3. In AutoFixture 2 you should be able to resolve it by creating the fixture like this:
var fixture = new Fixture().Customize(new StableMultipeCustomization());

Invalid call, the last call has been used or no call has been made

I am getting this error when I try to set a mock to have PropertyBehavior():
System.InvalidOperationException: System.InvalidOperationException:
Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)..
I am trying to use only Rhino Mocks 3.5 (Arrange, Act, Assert)
Here is my code:
private IAddAddressForm form;
private AddAddressMediator mediator;
[TestInitialize()]
public void MyTestInitialize()
{
form = MockRepository.GenerateMock<IAddAddressForm>();
mediator = new AddAddressMediator(form);
// Make the properties work like a normal property
Expect.Call(form.OKButtonEnabled).PropertyBehavior();
//I tried this too. I still get the exception
//SetupResult.For(form.OKButtonEnabled).PropertyBehavior();
}
[TestMethod]
public void TestOKButtonEnabled()
{
form.OKButtonEnabled = true;
Assert.IsTrue(form.OKButtonEnabled);
}
I know I could use a stub (and for the code above I should) but I am trying to learn Rhino Mocks.
Eventually I want to be able to make sure that several properties has their values accessed. (Any hints on how to check that form.FirstName was accessed (i.e. the getter was called) would also be appreciated.)
In case it is needed, here is the code to IAddressForm:
namespace AddressBook
{
public interface IAddAddressForm
{
string FirstName { get; set; }
string LastName { get; set; }
string Address1 { get; set; }
string State { get; set; }
string Address2 { get; set; }
string ZipCode { get; set; }
string City { get; set; }
bool OKButtonEnabled { get; set; }
}
}
Anyway, I thought that virtual would not be a problem as I am passing in an interface, but I am clearly missing something.
Never used PropertyBehavior before, but is this the syntax you're looking for?
form.Stub(x=>x.OKButtonEnabled).PropertyBehavior()
Rhino Mocks works completely through extension methods now. The only static call I every make any more is to MockRepository.GenerateStub.
You mentioned using a stub instead of a mock but before you go changing it I'd note that strangely, I get the Invalid Call exception when I used GenerateStub but not when I use GenerateMock.
View = MockRepository.GenerateStub<IAddressView>();
View.Stub(v => v.Message).PropertyBehavior();
This throws the Invalid call exception and yes, IAddressView.Message does have a getter and setter.
I received this error when I tried to set an expectation on a non-virtual method.
mockedObject.Expect(a => a.NonVirtualMethod()).Returns(null);
The error went away when I made NonVirtualMethod virtual.
I think you have to do MockRepository.ReplyAll() after you set up all expectations and before you start using this mock. So my guess in your case is that you have to move the Expect.Call line before mediator = new AddAddressMediator(form);, and stick the reply all right after that:
[TestInitialize()]
public void MyTestInitialize()
{
form = MockRepository.GenerateMock<IAddAddressForm>();
// Make the properties work like a normal property
Expect.Call(form.OKButtonEnabled).PropertyBehavior();
//I tried this too. I still get the exception
//SetupResult.For(form.OKButtonEnabled).PropertyBehavior();
MockRepository.ReplyAll();
mediator = new AddAddressMediator(form);
}
I ran into this issue when I was trying to call an internal property (getter only) on an object in C#. In this case, adding .PropertyBehavior() did not help.
My solution was to extract the logic out of the property and into an internal method which I then injected dependencies into this method (as parameters).

Categories

Resources