Create Mock Instances
The Mock the behavior of a public method topic demonstrated how to mock the behavior of a method using a plain object instance of the tested object. Coding using the best practices always involves creating abstract classes or interfaces. This topic shows you how you can test a functionality dependent on abstract classes or interfaces without caring about the specific implementations of the dependency.
To illustrate that case, we will use a slightly extended version of the example with orders and a warehouse. Now, we will define the warehouse as an interface and will enable a product to be delivered from multiple warehouses.
Sample setup
public interface IWarehouse
{
bool HasInventory(string productName, int quantity);
void Remove(string productName, int quantity);
}
public class Order
{
public Order(string productName, int quantity)
{
this.ProductName = productName;
this.Quantity = quantity;
}
public string ProductName { get; private set; }
public int Quantity { get; private set; }
public bool IsCompleted { get; private set; }
public void Complete(IWarehouse warehouse)
{
if (warehouse.HasInventory(this.ProductName, this.Quantity))
{
warehouse.Remove(this.ProductName, this.Quantity);
this.IsCompleted = true;
}
}
}
What would you need to do in order to verify that the Complete
method of the Order
class properly sets the IsCompleted
property? Let’s take a closer look - our target method depends on an instance implementing IWarehouse
that has some products currently present and internally invokes other two methods - HasInventory
and Remove
. Testing this case without using a mocking framework will force you to find a specific instance of a warehouse and control its data so that the Complete
method of Order
can perform the needed actions.
JustMock enables you to create instances of abstract classes and interfaces without providing their exact implementations. You also have control over how they should be mocked. Example 1 demonstrates how you can use the Mock.Create()
method to get an instance representing IWarehouse
.
Example 1: Create mock from an interface
[TestMethod]
public void Order_IsCompleted_WhenWarehouseHasInventory()
{
// Create an instance of the class
Order order = new Order("testProduct", 10);
// Get an instance of the interface dependency
IWarehouse warehouse = Mock.Create<IWarehouse>();
// Setup the warehouse - the HasInventory method called with the specified parameters will always return true.
Mock.Arrange(() => warehouse.HasInventory(order.ProductName, order.Quantity)).Returns(true);
// We are not maintaining a collection of products, so there isn't anything to remove.
Mock.Arrange(() => warehouse.Remove(order.ProductName, order.Quantity)).DoNothing();
order.Complete(warehouse);
Assert.IsTrue(order.IsCompleted);
}
The parameterless overload of the Create()
method generates an instance of the mocked class or interface using the RecursiveLoose behavior. The following list will give you a brief overview of the different mock behaviors you can use.
RecursiveLoose behavior: Generate empty stubs for all members and dependencies. Even if nothing is arranged, the mocks with Behavior.RecursiveLoose never return null. This is the default behavior. Read more in the Behaviors|RecursiveLoose article.
Loose behavior: When nothing arranged, the members return the default value of their return type - null for reference types and the default value for value types. Read more in the Behaviors|Loose article
CallOriginal behavior: All members follow the original implementation of the mocked instance. Read more...
Strict behavior: Allows you to call only arranged methods. Every call to other members results in MockException. Read more in the Behaviors|Strict article
Create mock of a type using non-default constructor
In addition to passing the mock behavior, the overloads of the Create
method allow you specify the constructor you would like to use. Depending on the specific class implementation, it might miss a default constructor, or you might need to test the behavior of an object when created with specific arguments.
In the sample setup used in this topic, the Order class doesn't provide a default constructor, so we will need to provide the required parameters if we need to create an object of that type.
Example 2: Create mock using non-default constructor
Order orderMock = Mock.Create<Order>(Behavior.CallOriginal, "test product", 1);
Next Steps
Check the Arrange topic to learn more on how you can setup the desired behavior of different members.