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.
Related
Value objects in DDD are immutable, the properties are typically set once via the constructor.
I sometimes require a copy of a value object with only some changes, e.g. ten of the properties should be copied and one property will get a new value. In this case I want to avoid using a constructor with eleven parameters, instead I want to implement a method that returns a copy but at the same time applies some changes to the properties. I know I can do this via reflection but would like to check if it is possible to avoid reflection.
public class Foo
{
public int Bar { get; set; } // actual use case is { get; private set; }
public Foo(int bar)
{
Bar = bar;
}
public Foo CloneAndApply(Action<Foo> apply)
{
var result = new Foo(Bar);
apply(result);
return result;
}
}
This works because the "Bar" property has a public setter. I require something that allows setting "Bar" when it is a private member.
var test = new Foo(1);
var clone = test.CloneAndApply(x => x.Bar = 2);
Console.WriteLine(clone.Bar);
You might be interested in Records, introduced in C# 9. Records contain many parts, but one of them is support for "withers", which interact with the new init-only properties to easily let you create modified copies of records.
Records support things like primary constructors, which I'm going to gloss over here. At a simple level, your record might look like:
public record Foo
{
public int Bar { get; init; }
public Foo(int bar)
{
Bar = bar;
}
}
and could be used as:
var foo = new Foo(3);
var foo2 = foo with { Bar = 4 };
This record also automatically implements equality, based on the equality of its individual members, and an overridded ToString implementation.
The long-term plan is to allow withers to be used with non-record types, although (as of C# 9) this is not yet supported.
If you take advantage of primary constructors, you can write your record even more concisely:
public record Foo(int Bar);
This auto-generates the Bar property, with get and init accessors, and a constructor which assigns to it.
I achieve this pre .net5's records with WithX methods that pass the property that needs to be different. It's not fancy but it works.
public class Foo
{
public int X { get; private set; }
public int Bar { get; private set; }
public Foo(int x, int bar) { X = x; Bar = bar; }
public Foo WithBar(int bar) => new Foo(X, bar);
}
}
Another solution might be reflection. This can also be used to assign values to private properties:
class Program
{
static void Main(string[] args)
{
var test = new Foo(1);
var clone = test.CloneAndApply(x => x.GetType().GetProperty("Bar").SetValue(x, 2));
Console.WriteLine(clone.Bar);
}
}
public class Foo
{
public int Bar { get; private set; }
public Foo(int bar)
{
Bar = bar;
}
public Foo CloneAndApply(Action<Foo> apply)
{
var result = new Foo(Bar);
apply(result);
return result;
}
}
I have a class like this:
public class MyClass
{
private MyStruct _someProperty;
public MyStruct SomeProperty
{
set
{
if(StructureChanged(_someProperty, value))
{
_someProperty = value;
OnSomePropertyChanged();
}
}
}
private bool StructureChanged(MyStruct oldValue, MyStruct newValue)
{
// Check if any property of newValue is different from oldValue
// This is a check for semantic equality, not referential equality
}
internal protected virtual OnSomePropertyChanged()
{
// ...
}
}
And a test like this:
// Arrange
_myClass = MockRepository.GeneratePartialMock<MyClass>();
_myClass.SomeProperty = new MyStruct();
// Act
_myClass.SomeProperty = new MyStruct(); // This is semantically equal to the current value
// Assert
_myClass.AssertWasNotCalled(m => m.OnSomePropertyChanged());
Of course, the test fails because OnSomePropertyChanged is called when I set the property the first time. What I want is to set the property the first time, reset the AssertWasNotCalled value somehow, and then set the property again and make sure OnSomePropertyChanged is not called again. Is there any way to do this?
Actually, in that case this is expected that OnSomePropertyChanged() is called once. But not more and not less than once.
The suitable assert statement then might look like:
_myClass.AssertWasCalled(m => m.OnSomePropertyChanged(), opt => opt.Repeat.Once());
PS
Another test should be written which ensures OnSomePropertyCnahged() is triggered after SomeProperty is actually changed.
In that case in our test it is guaranteed OnSomePropertyCnahged() is triggered when SomeProperty was changed first time.
And expectation it is called once, but not two times, guarantees that event is not fired when that is not expected.
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
I have this scenario, which I think must be pretty common:
class Parameter
{
public int someInt;
private decimal someDecimal;
public SubParameter subParameter;
}
class SubParameter
{
public string someString { get; set; }
}
I have a breakpoint at a call to a method that takes a Parameter as a parameter. I want to write a unit test where I call this method with the same exact value (a copy of the Parameter object "tree").
It is very tedious in this case to write the many lines declaring and initializing all the fields and properties of the class, which themselves might be non-primitive etc.
It would be nice if I could just right-click on the parameter variable and then have code auto-generated to create such an object.
So if at my breakpoint, my Parameter object has the value
Parameter parameter = new Parameter
{
someInt = 42,
someDecimal = 42.42m,
subParameter = new SubParameter { someString = "42" }
};
well, then that code would be generated. I could then use the generated code for my unit test.
Does such a thing exist?
Edit:
I guess I have been unclear. I know perfectly well how to write the code myself by hand.
What I want is that when I am hitting a breakpoint and watching a complex variable (or any variable for that matter), I want to be able to say: Generate code for me that creates a clone of this variable. I would use the generated code for my unit test.
Does such a tool exist?
Just create a helper method to create the parameter for you:
public void CreateParameter()
{
return new Parameter
{
someInt = 42,
someDecimal = 42.42m,
subParameter = new SubParameter { someString = "42" }
};
}
Sample use
[TestMethod]
public void MyTest()
{
SomeClass.MethodBeingTested(CreateParameter());
}
If you want to have a specific parameter value then modify the returned parameter or provide an overload which allows you to supply that value:
[TestMethod]
public void MyTest()
{
Parameter parameter = CreateParameter();
parameter.someInt = 23;
SomeClass.MethodBeingTested(parameter);
}
I usually have my CreateParameter populate the parameter with random values to reduce the possibility that the unit test happens to pass "by chance" for certain values, but will fail for others.
You can use TestInitialize for initialize test methods:
[TestClass]
public class UnitTest1
{
Parameter _parameter = null;
[TestInitialize]
public void Initialize()
{
_parameter = new Parameter
{
someInt = 42,
someDecimal = 42.42m,
subParameter = new SubParameter { someString = "42" }
};
}
[TestCleanup]
public void Cleanup()
{
_parameter = null;
}
[TestMethod]
public void MyTest1()
{
// test _parameter
}
[TestMethod]
public void MyTest2()
{
// test _parameter
}
}
I am having problems setting the value of a property in Rhinomocks. I need to set the initial value of the property outside the method under test and then set its value inside the method under test conditionally. Some code:
public interface IResponse
{
string ResponseText { get; set; }
}
public void ProcessResponse(IResponse response)
{
if(response.ResponseText == "Unset")
{
response.ResponseText = someService.GetResponse();//someService here is irrelvant to the question
}
}
[TestMethod]
public void ResponseValueIsSetWhenConditionIsTrueTest()
{
var mock = Mock<IResponse>.GenerateMock();
mock.Stub(x => x.ResponseText).Returns("Unset");
Processor.ProcessResponse(mock);
Assert.AreEqual("Responseval", mock.ResponseText); //Fails because the method doesn't set the value of the property.
}
I need the mock's property to have an initial value going into the Act part of the test, and allow the method under test to change that value so I can assert on it later. However mock.ResponseText is always set to "Unset", and the method never changes its value - what is going on here?
Have you tried PropertyBehavior? For example:
mock.Stub(x => x.ResponseText).PropertyBehavior();
Then in your test:
mock.ResponseText = "Unset";
Processor.ProcessResponse(mock);
Assert.AreEqual("Responseval", mock.ResponseText);
First of all, there's a difference in behavior between mocks and stubs in Rhino.Mocks. Secondly, I'm not sure what version of Rhino.Mocks you are using, but using the latest one and AAA syntax, this certainly works:
public interface IResponse
{
string ResponseText { get; set; }
}
...
[Test]
public void Test()
{
IResponse response = MockRepository.GenerateStub<IResponse>();
response.ResponseText = "value1";
Assert.AreEqual("value1", response.ResponseText);
response.ResponseText = "value2";
Assert.AreEqual("value2", response.ResponseText);
}