Mock Properties
Mocking properties is similar to mocking methods, but there are a few cases that need special attention like mocking indexers and particular set operations.
To illustrate the usage of the functionality, we will be using the following interface definition:
Sample setup
public interface IFoo
{
int Value{get; set;}
}
Public Interface IFoo
Property Value() As Integer
End Interface
Property Getter
The property get can be mocked like any other method call. You can arrange a return statement for a specific call (using Returns), throw an exception (using Throws), raise an event when invoked (using Raise), etc.
Let's consider the following example:
Example 1: Arrange the return value of a getter
[TestMethod]
public void ShouldFakePropertyGet()
{
// Arrange
var foo = Mock.Create<IFoo>();
Mock.Arrange(() => foo.Value).Returns(25);
// Act
var actual = foo.Value;
// Assert
Assert.AreEqual(25, actual);
}
<TestMethod()>
Public Sub ShouldFakePropertyGet()
' Arrange
Dim foo = Mock.Create(Of IFoo)()
Mock.Arrange(Function() foo.Value).Returns(25)
' Act
Dim actual As Integer = foo.Value
' Assert
Assert.AreEqual(25, actual)
End Sub
Here we test that a call to foo.Value property returns the value we arranged.
Property Setter
The set operation can be mocked for both indexers and normal properties. Set operations are mocked using a special set entry point which is Mock.ArrangeSet(lambda).
Property set mocking is useful when you want to make sure or to verify that a particular property is set with an expected value. For this reason, we use a strict mocking.
Example 2: Mock setter when mocking behavior is Strict
[TestMethod]
[ExpectedException(typeof(StrictMockException))]
public void ShouldThrowExceptionOnTheThirdPropertySetCall()
{
// Arrange
var foo = Mock.Create<IFoo>(Behavior.Strict);
Mock.ArrangeSet(() => foo.Value = Arg.Matches<int>(x => x > 3));
// Act
foo.Value = 4;
foo.Value = 5;
// throws MockException because matching criteria is not met
foo.Value = 3;
}
<TestMethod()>
<ExpectedException(GetType(StrictMockException))>
Public Sub ShouldThrowExceptionOnTheThirdPropertySetCall()
' Arrange
Dim foo = Mock.Create(Of IFoo)(Behavior.Strict)
Mock.ArrangeSet(Sub() foo.Value = Arg.Matches(Of Integer)(Function(x) x > 3))
' Act
foo.Value = 4
foo.Value = 5
' throws MockException because matching criteria is not met
foo.Value = 3
End Sub
With the Arg.Matches<int> matcher, we set a requirement that the foo.Value property should have values larger than 3. When we set the value to a number less than 3, a MockException is thrown.
For more details on how to work with arguments and matchers, check the Matchers help topic.
For asserting a property set in case of loose mocking, the following syntax is available:
Mock.AssertSet(lambda).
Accordingly, we can do:
Example 3: Mock setter when mocking behavior is Loose
[TestMethod]
public void ShouldAssertPropertySet()
{
// Arrange
var foo = Mock.Create<IFoo>();
Mock.ArrangeSet(() => foo.Value = 1);
// Act
foo.Value = 1;
// Assert
Mock.AssertSet(() => foo.Value = 1);
}
<TestMethod()>
Public Sub ShouldAssertPropertySet()
' Arrange
Dim foo = Mock.Create(Of IFoo)()
Mock.ArrangeSet(Sub() foo.Value = 1)
' Act
foo.Value = 1
' Assert
Mock.AssertSet(Sub() foo.Value = 1)
End Sub
Here we make sure foo.Value was actually set to 1.
Refer to Do Instead for an example that shows how to use
DoInsteadon property set.
Indexers
Indexers are special kind of properties that enable objects to be indexed in a similar manner to arrays.
Consider an interface with an indexer property.
Sample setup
public interface IIndexedFoo
{
string this[int key] { get; set; }
}
Public Interface IIndexedFoo
Default Property Item(key As Integer) As String
End Interface
Example 4 shows how you can control the return value of an indexer property getter.
Example 4: Return different values for different indexes
// Create mock
var indexedFoo = Mock.Create<IIndexedFoo>();
// Arrange that a call to index 0 should return ping, a call to index 1 should return pong.
Mock.Arrange(() => indexedFoo[0]).Returns("ping");
Mock.Arrange(() => indexedFoo[1]).Returns("pong");
// Act
string actualFirst = indexedFoo[0];
string actualSec = indexedFoo[1];
// Assert
Assert.AreEqual("ping", actualFirst);
Assert.AreEqual("pong", actualSec);
' Create mock
Dim IndexedFoo = Mock.Create(Of IIndexedFoo)()
' Arrange that a call to index 0 should return ping, a call to index 1 should return pong.
Mock.Arrange(Function() IndexedFoo(0)).Returns("ping")
Mock.Arrange(Function() IndexedFoo(1)).Returns("pong")
' Act
Dim actualFirst As String = IndexedFoo(0)
Dim actualSec As String = IndexedFoo(1)
' Assert
Assert.AreEqual("ping", actualFirst)
Assert.AreEqual("pong", actualSec)
Assert Indexer Set
Make sure that a specific index is set to a particular value.
Example 5: Arrange indexer setter
[TestMethod]
[ExpectedException(typeof(StrictMockException))]
public void ShouldThrowExceptionForNotArrangedPropertySet()
{
// Arrange
var foo = Mock.Create<IIndexedFoo>(Behavior.Strict);
// foo[0] can be only set to "foo".
Mock.ArrangeSet(() => { foo[0] = "foo"; });
// Act
foo[0] = "foo";
// The following line does not satisfy the arranged criteria and throws a StrictMockException.
foo[0] = "bar";
}
<TestMethod()>
<ExpectedException(GetType(StrictMockException))>
Public Sub ShouldThrowExceptionForNotArrangedPropertySet()
' Arrange
Dim foo = Mock.Create(Of IIndexedFoo)(Behavior.Strict)
' foo[0] can be only set to "foo".
Mock.ArrangeSet(Sub() foo(0) = "foo")
' Act
foo(0) = "foo"
' The following line does not satisfy the arranged criteria and throws a StrictMockException.
foo(0) = "bar"
End Sub
The code above throws an exception once the zero-indexed item of foo is set to a value different than the expected one - i.e. foo.
Assert Indexer Set with Matching Criteria
Make sure that a specific index is set to a value matching a particular criteria.
Example 6: Arrange indexer setter using matchers
[TestMethod]
[ExpectedException(typeof(StrictMockException))]
public void ShouldAssertIndexedSetWithMatcher()
{
// Arrange
var foo = Mock.Create<IIndexedFoo>(Behavior.Strict);
// foo[0] can be only set to "ping".
Mock.ArrangeSet(() => { foo[0] = Arg.Matches<string>(x => x.Equals("ping")); });
// foo[1] can be only set to any string.
Mock.ArrangeSet(() => { foo[1] = Arg.IsAny<string>(); });
// Act
foo[0] = "ping";
foo[1] = "pong";
// The following line does not satisfy the matching criteria and throws a MockException.
foo[0] = "bar";
}
<TestMethod()>
<ExpectedException(GetType(StrictMockException))>
Public Sub ShouldAssertIndexedSetWithMatcher()
' Arrange
Dim foo = Mock.Create(Of IIndexedFoo)(Behavior.Strict)
' foo[0] can be only set to "ping".
Mock.ArrangeSet(Sub() foo(0) = Arg.Matches(Of String)(Function(x) x.Equals("ping")))
' foo[1] can be only set to any string.
Mock.ArrangeSet(Sub() foo(1) = "pong")
' Act
foo(0) = "ping"
foo(1) = "pong"
' The following line does not satisfy the matching criteria and throws a MockException
foo(0) = "bar"
End Sub
The first two set calls satisfy the requirements. However, the third call - foo[0] = "bar" throws an exception, because we arranged that the zero-indexed item can be set only to "foo".