I am trying to understand why mocking behaves in such a way (I'm using NUnit with Moq). Let's say, we have a simple class:
public class Package
{
public virtual int PackageId { get; set; }
public Package()
:this(-1)
{
}
public Package(int packageId)
{
PackageId = packageId;
}
}
And some simple tests to discuss:
[TestFixture]
public class NUnitTrickyTest
{
private const int SamplePackageId = 10;
[Test]
public void TestPackageSetUp_WhenMockedWithDefaultConstructor_ExpectSamplePackageIdSet()
{
var samplePackage = new Mock<Package>();
samplePackage.SetupProperty(x => x.PackageId, SamplePackageId);
Assert.AreEqual(SamplePackageId, samplePackage.Object.PackageId);
}
[Test]
public void TestPackageSetUp_WhenMockedWithParametrizedConstructor_ExpectSamplePackageIdSet()
{
var samplePackage = new Mock<Package>(SamplePackageId);
// samplePackage.SetupProperty(x => x.PackageId, SamplePackageId);
Assert.AreEqual(SamplePackageId, samplePackage.Object.PackageId);
}
}
The first test fails as samplePackage.Object.PackageId returns -1, not 10 as expected. As I understand mocked Package() calls parameterized constructor which initializes the property with default -1. In the second test we find samplePackage.Object.PackageId returning 0.
The first thing I don't understand why 0 was returned (in debug I saw that 10 was passed in the constructor, but the property remained 0 value). The second one: if we uncomment this command samplePackage.SetupProperty(x => x.PackageId, SamplePackageId) in the second test, it will succeed. So why SetupProperty behaves as expected in that case (property returns 10), and not in such a way in the first test?
Could you please help? This is my first post so don't be severe :)
All mockable (virtual) methods use a proxy by default, so that is why you get a default value (0) on the second test (the proxy is not set). You can get around this by setting CallBase = true on your mock, though.
CallBase = true will use default implementations if available instead of trying to mock everything out.
It took me a second to figure out the reason for the first one failing and I believe that this is because SetupProperty only turns on tracking with a default value and since you are overriding that default value in the constructor then that is what is used. If you want to force a value then you need to use Setup(x=>x.PackageId).Returns(SamplePackageId) or SetupGet
Related
Let's say I have a simple class called MyRequestHandler, and it has a method called ProcessRequest that simply takes a request object, maps it to a return object and returns that object. (This is obviously a very simple example of a much more complex method/test that I'm working on).
public class MyRequestHandler
{
private IMapper _mapper;
public MyRequestHandler(IMapper maper)
{
_mapper = mapper;
}
public MyReturnObject ProcessRequest(MyRequestObject requestObject)
{
MyReturnObject returnObject = _mapper.Map<MyReturnObject>(requestObject);
return returnObject;
}
}
Now for unit testing (using Xunit), I want to test the ProcessRequest method, but obviously want to Moq the Map method, as such:
MyRequestObject requestObject = new RequestObject()
{
RequestInt = 1,
RequestString = "Hello"
};
MyReturnObject returnObject = new MyReturnObject()
{
MyInt = 1,
MyString = "Hello"
};
Mock<IMapper> mockMapper = new Mock<IMapper>();
mockMapper.Setup(m => m.Map<MyRequestObject>(requestObject)).Returns(returnObject);
MyRequestHandler requestHandler = new MyRequestHandler(mockMapper.Object);
MyReturnObject response = requestHandler.ProcessRequest(requestObject);
Assert.Equal(returnObject.MyInt, response.MyInt);
Assert.Equal(returnObject.MyString, response.MyString);
The problem here is that Moq returns (and I guess it should be obvious that it is) a reference to returnObject, so my Asserts will always pass, even if my method were to change a value prior to returning the object. Now I could instantiate a new MyReturnObject in the Moq Setup/Return and compare the MyInt and MyString by the values I give to the new one, but what if it's a really complex object with 20 properties and lists of objects? Maybe I want to use AutoFixture to create the object being returned and use DeepEqual to compare them? Is this even possible? Am I looking at this wrong, or do I have to do some type of cloning in the Setup/Return to make this work?
I don't believe there is built in functionality to detect that method under test did not change object passed to it.
Options:
make sure that return objects are immutable - either by having them immutable to start with or by returning interface without "set" methods with an instance created via mocks
create separate instance for "expected" and "mocked" values and then compare property-by-property. There are plenty of helper libraries to do so (I like FluentAssertions).
just assert on individual properties instead of comparing objects - works fine for small number of fields.
If possible I'd prefer immutable objects - that prevent possibility of writing wrong code and thus decreases amount of testing needed.
In this case you didn't receive a new data and can verify behavior
Internal state is not valuable in this case
var requestObject = new RequestObject();
var returnObject = new MyReturnObject();
...
var actual = requestHandler.ProcessRequest(requestObject);
Assert.AreSame(returnObject, actual);
mockMapper.Verify(
instance => instance.Map<MyRequestObject>(requestObject),
Times.Once);
Some details
we can't share write access with others, so i assume you have
public class MyRequestObject
{
int RequestInt { get; private set; }
string RequestString { get; private set; }
}
otherwise you always should test for parameter mutation. You can imagine 10 participants called in depth and each of them should have such tests. These tests will weak against changes, they do nothing with new properties.
It is better to have good coding convention and do codereview sometimes. In example someone can randomly remove private from property and it can't be catched with any tests.
There are many good practices in example "write test before of code" and so on
I use Vs2015 with NSubstitute 3.1.0.
This code is passed but shouldn't.
public class Test
{
public string[] Content { get; set; }
}
[Fact]
public void Should_What()
{
var obj = Substitute.For<Test>();
var test = obj.DidNotReceive().Content;
var test2 = obj.Received().Content;
}
If replace class Test to interface it will works well, but in my test I have class.
How to check if property Content has been used ?
The solution is to use virtual for the property.
public virtual string[] Content { get; set; }
But, if two opposing tests return the True at the same time, we have a bug.
Can explain why and indicate a solution, but this is a workaround.
In my opinion it should throw an exception (ex. NotSupportedException, when a test is executed on non-virtual properties).
The testing environment is expected to detect the problems. So it should be pessimistic.
In this case should be better to return false instead of true. To sign the developer the problem (even if it is in the framework).
For example in SQL when try to check null value, will always return false (null == true, null == 0 or even null == null).
This is just my point.
What do you guys think about it?
I've recently got a small headache during unit testing one of my property setters. I wanted to setup my property to return a certain value and do not invoke setter logic because it has some heavy operations in there and I don't want that logic to affect my unit test.
I know I can move that logic to a method and then mock that new method instead but that problem made me curious and I've dug a little.
The results of my research is in FooTests class below, one of them using SetupProperty works, but makes me feel that this is not what this method is written for.
Is there a dedicated way to short-circuit setters in partial mocks in Moq?
Foo.cs:
public class Foo
{
private int _bar;
public virtual int Bar
{
get => _bar;
set
{
MagicNumber+=FooBar;
_bar = value;
}
}
private int _fooBar;
public virtual int FooBar
{
get => _fooBar;
set
{
//Complex and heavy logic that makes the magic number -value
MagicNumber = -value;
_fooBar = value;
}
}
public int MagicNumber { get; set; }
public Foo()
{
FooBar = 1;
}
}
FooTests.cs:
[TestFixture]
public class FooTests
{
//Using ordinary setup.
[TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo")]
public void BarSetterTest(int bar, int fooBar, int expectedMagicNumber)
{
var fooPartialMock = new Mock<Foo> {CallBase = true};
fooPartialMock.Setup(x => x.FooBar).Returns(fooBar);
fooPartialMock.Object.Bar = bar;
Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
}
//Using callbacks.
[TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo2")]
public void BarSetterTest2(int bar, int fooBar, int expectedMagicNumber)
{
var fooPartialMock = new Mock<Foo> { CallBase = true };
fooPartialMock.SetupSet(x => x.FooBar = It.IsAny<int>()).Callback<int>(x => {});
fooPartialMock.Object.Bar = bar;
Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
}
//Using SetupProperty.
[TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo3")]
public void BarSetterTest3(int bar, int fooBar, int expectedMagicNumber)
{
var fooPartialMock = new Mock<Foo> { CallBase = true };
fooPartialMock.SetupProperty(x => x.FooBar);
fooPartialMock.Object.FooBar = fooBar;
fooPartialMock.Object.Bar = bar;
Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
}
}
The difference in results of the tests is caused by different behavior of Mock, that was configured. Method Setup In the first test just override getter method:
Specifies a setup on the mocked type for a call to a value returning method.
So in this case call of FooBar in constructor affects MagicNumber. Overloading of method SetupSet you used in second test is obsolete, and looks like it doesn't override the setter, it just set up an expectation, that you can verify later? on or add a callback:
Specifies a setup on the mocked type for a call to to a property setter, regardless of its value.
In this case FooBar in constructor affects the MagicNumber too. However FooBar setter is called twice: from constructor and from lambda, where it called with return value of It.IsAny<int>, which is 0. At last, SetupProperty from the third test sets up default property behavior:
Specifies that given property should have a property behavior, meaning that setting its value will cause it to be saved and later returned when the property is requested(this is also known as stubbing)
So FooBar in constructor doesn't affect MagicNumber in the third test, because the whole property is covered with stub, and you never get to FooBar setter. Therefore the third test is green. I suppose that configuration, that you implemented in third test, do what you need. You can combine it with the first one to make FooBar getter always return the same value:
fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);
Hope it helps.
I've come across a problem when writing a unit test where in the method I'm calling it doesn't modify the mock object I've passed in. I'm not sure if there's just something obvious I'm missing?
I've setup the mock as follows:
var mockList = new List<Mock<IDocument>>();
for (int i = 0; i < 4; i++)
{
var mockDocument = new Mock<IDocument>();
mockDocument.Setup(t => t.DocumentNo).Returns(i.ToString());
mockList.Add(mockDocument);
}
mockDocumentRepository.Setup(x => x.GetDocuments(It.IsAny<string>(), It.IsAny<string>()))
.Returns(mockList.Select(m => m.Object).ToList());
In the executed method, if I attempt to modify another property on the mocked class (for example t.DocumentName) the value remains Null. Is there anyway to setup that property to accept a modification?
The reason I'm doing this is to test whether the collection of documents has been modified by another collection in the method. Not sure if there's better way's of doing this?
Moq will leave all methods unimplemented unless instructed to do otherwise, and that includes properties. If you use mockDocument.SetupProperty(doc => doc.DocumentName); it will implement the property as a regular auto-property. You can use mockDocument.SetupAllProperties() if you want all properties to be auto-implemented, but you'll still have to do it for every mock object.
You could also consider making a stub instead of a mock:
public class StubDocument : IDocument
{
public string DocumentNo { get; set; }
public string DocumentName { get; set; }
...
}
In general, I find that stubbing is often preferable to mocking when dealing with very simple interfaces, as seems to be the case with your IDocument.
In my project I have one class called Area like below.
The property "CodArea" I want to put one custom attribute like [NaoSelecionarAttr(true)].
This is working fine but when I create one instance of the class I can not get this custom attribute. Something like this:
Area areaPoco = new Area();
areaPoco.CodArea.GetType().GetCustomAttributes(typeof(NaoSelecionarAttr),true).ToList();
[Serializable]
public class Area
{
#region Private Members
private decimal _numChave;
private string _codArea;
public Area()
{
_numChave = 0;
_codArea = null;
}
public Area(decimal pNumChave, string pCodArea)
{
NumChave = pNumChave;
CodArea = pCodArea;
}
public virtual decimal NumChave
{ get { return _numChave;}
set { _numChave = value;}
}
[NaoSelecionarAttr(true)]
public virtual string CodArea
{
get { return _codArea; }
set { _codArea = value;}
}
}
public class NaoSelecionarAttr : Attribute
{
public bool NaoSelecionar { get; set; }
public NaoSelecionarAttr(bool pSim) { this.NaoSelecionar = pSim; }
}
}
There are some problems with your code.
The first problem in the code is that you are calling the default constructor on Area, which initializes _codArea to null. And then you try to call GetType on it, which fails with a NullReferenceException, as expected.
The second problem is that you want an attribute of a property of a class. So you must inspect (or reflect) the class, not the property. You see, when you write areaPoco.CodArea... the compiler resolves it to the result of your get expression, in this case, the field _codArea. By calling GetType() on _codArea, what you retrieve is a String type, not your Area type. I know this may seem confusing at first, but properties aren't types, so you can't reflect on them.
What you should do, then, is:
Area areaPoco = new Area();
NaoSelecionarAttr attr = (NaoSelecionarAttr) (areaPoco.GetType().GetProperties().Single(p => p.Name == "CodArea").GetCustomAttributes(typeof(NaoSelecionarAttr), true).Single());
bool naoSelecionar = attr.NaoSelecionar;
If I may, I want to give you some tips as well:
Your notation for the non-default constructor seems reminiscent of C/C++. There usually isn't a good reason to stick a "p" prefix in the parameters.
Instead of NaoSelecionar, which is a negative property, I recommend you work with "Selecionar". The deal is that you can easily confuse a negative sentence with its correspondent positive one. A month from now you will ask, "ok, the parameter is false, so should I select or not this property?". False usually means NOT, so, your default interpretation would be not to select something when the property is false.
Your default constructor is initializing a property to null. Just as I described above, this can result in bugs. Either initialize it to a default value (string.Empty), or remove the default constructor and use only the one that requires the user to provide a value to string. And validate those parameters as well -- the user might provide again a null to the string. (An object should be valid when first constructed)
One final tip. Your NaoSelecionar attribute gets a boolean parameter. The last bullet was exactly about that -- you can confuse whether having a true property for your attribute means "não" or "sim". Well, why don't you simply remove the parameter and then work with a negative parameter? There's no need to pass true or false to NaoSelecionar, since all you need to do is iterate through your class and find which properties have this attribute applied to them.
Why do you use areaPoco.CodArea.GetType()? I think you should use areaPoco.GetType(). Because your custom attribute belongs to the Area class, not to the string.