// Impleme this:
public
bool
Execute(
decimal
amount)
{
if
(!_provider.Reserve(amount))
return
false
;
if
(!_provider.Execute(amount))
return
false
;
return
true
;
}
Even though we have the actual code in front of us, it is not important! What is important is that we just understand that we first need to reserve the amount and then if that succeeds we execute the payment which finalizes the process.
We’ve looked almost all parts of the system, but where is the implementations of the
IPaymentProvider?
Let’s assume we don’t have it! Even though we don’t have access to the implementation at this time (maybe we haven’t made it quite yet, we might not even know what payment providers we are implementing the system against) we still want to
test the process of the Execute method, we want to assure that no exceptions are thrown and that based on a Reservation that did not go through, we don’t want it to go any further.
In the article on
IoC and DI we talked about introducing fakes by creating “dumb” implementations that only did what we asked of them. This is indeed one way to go but let us take a look at another approach of this. Let’s look at a Mocking Framework!
There are a lot of mocking frameworks out there for .NET, here are two that are very good (among many many others):
But I’ve decided to go with Simple.Mocking. We can install this with NuGet, this is how the test-project I’ve created look like before I use NuGet to install Simple.Mocking:
Now fire up the nuget manager and write:
PM> Install-Package Simple.Mocking
You should now see something like this:
Now we’re ready to start mocking!
There are a couple of important parts in Simple.Mocking that we’re going to cover now, the first one is: How do we fake an instance of our
IPaymentProvider?
Start off by adding a reference to the framework by adding this to the top of the file:
Now, there’s a class we can access called
Mock here we’ve got two different methods that will let us do two things:
- Mock.Interface will let us fake an implementation of our interface as if we had a real implementation.
- Mock.Delegate will let us fake a delegate, we won’t be looking in to this anything in this article.
Of these two we will only concentrate on Mock.Interface. You easily fake/mock an implementation by doing this:
var provider = Mock.Interface<IPaymentProvider>();
Is this it? No, it’s not! We’ve still got a path to wander before we’ve reached our final destination. If we check what methods we have on the variable provider this is what we got:
So what happens if we run the following code:
var provider = Mock.Interface<IPaymentProvider>();
provider.Execute(100);
It does look valid, doesn’t it? The problem here is that the method Execute has not idea of how it should behave so it will raise an exception. Because it expects us to define a behavior for it before we proceed. This brings us to the next interesting object
that we are going to take a look at that comes with
Simple.Mocking; Expect!
Almost all the methods on the Expect
type takes an expression of type Action
or Func, at least the ones we are interested in at the moment. These are the most commonly used methods:
- Expect.MethodCall
- Expect.PropertyGet
- Expect.PropertySet
- Expect.AnyInvocationOn
From their names you should be able to figure out what they do, but we’re going to look closer at
Expect.MethodCall now.
Expect.MethodCall is used to define an expected call to a method on a given type. Take a look at this example:
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(10));
This fakes an implementation of the interface
IPaymentProvider and says that it expects us to call provider.Reserve with the amount 10. If we were to invoke it with another value, let’s say 0 like this:
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(10));
provider.Reserve(0);
We would get an exception because it assumes that we are about to call it with the amount 10:
IPaymentProvider
and says that it expects us to call provider.Reserve wiking-Framework-Microsoft-Visual-Studio-Administrator-5.png" />
Unexpected invocation ‘paymentProvider.Reserve(0)’, expected:
(invoked: 0 of *) paymentProvider.Reserve(10)
So if we change that to 10, it should be all good, but it’s not always that you want to hard-code a constant value like that, so what you can use is a helper class called
Any<T>
which will let us define any type as an in-parameter or as a return value. In order to say that we are expecting a parameter type of decimal we do this:
But that’s not enough, this only defines the type, we need to use the property Value in order to use the actual value that we will use later when we call this method:
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value));
provider.Reserve(0);
provider.Reserve(25);
This means that the first time Reserve
is called, the value of the decimal sent to the fake method will be 0 and the second time it will be 25. Let’s make it a little interesting, as you might have noticed, you can define a lot of different Expectations for the same method, the parameter
values are what defines what mocked invocation to use.
There’s a method called Matching on the Value parameter that you can use to distinguish between different values. For instance, you might want to make a very specific test where it fails when the amount is less than 10 and succeeds when the value is above.
That could look something like this:
Expect.MethodCall(() => provider.Reserve Any<
decimal
>.Value.Matching(amount
=> amount > 10)));
This mocked method call will be used when we call Reserve with an amount greater than 10. But we’re still not returning either true nor false, that’s the next part! This is probably the easiest part so far, right before the semi-colon, just add
.Returns(true); and you’re all set!
So this is what the result of this snippet looks like:
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value.Matching(amount
=> amount > 10)))
.Returns(
true
);
And if we want to add another expectation that returns false if it is less or equal to 10, we can do that as well, the entire code will look something like this:
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value.Matching(amount
=> amount > 10)))
.Returns(
true
);
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value.Matching(amount
=> amount <= 10)))
.Returns(
false
);
provider.Reserve(0);
);
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value.Matching(amount
=> amount <= 10)))
&"color:#000000;">provider.Reserve(25);
The first reservation will return false, because amount is less than 10 but the second one will use the first faked method call and return true. Now let’s step back a bit and take a look at our original problem, we want to make sure that we can process a
payment and it should fail when the reservation fails and succeed when the reservation succeeds. So let’s remove all the fuss around that and we should be left with a pretty simple looking snippet like this:
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value)).Returns(
true
);
Now the next steps are pretty straight forward, we need to do the following:
- Create an expectation for the method call Execute
- Create an instance of the Payment type and pass it the mocked interface
- Execute a payment process!
- Validate the results by using tests
The next expected method call is the Execute method on the payment provider, this will look almost identical to the Reserve method in this case:
Expect.MethodCall(() => provider.Execute(Any<
decimal
>.Value)).Returns(
true
);
The last two things we need to do now is to create an instance of our payment processor and pass it the interface:
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value)).Returns(
true
);
Expect.MethodCall(() => provider.Execute(Any<
decimal
>.Value)).Returns(
true
);
var payment =
new
Payment(provider);
payment.Execute(200);
This should compile fine and when you run the test it shouldn’t complain anything at all. Now we’ve got everything set up, we need to test the behavior of payment processor and the two scenarios are:
- If reservation fails, execute should never be invoked
- If reservation succeeds, execute should be invoked and the method should return true
There are a couple of more scenarios such as, in the rare occasion if the reservation succeeds but the execution does not, does it throw a proper exception and roll back? But I’ll leave these special scenarios for you to play with.
Let’s continue looking at the first test, we’ve already (partially) finished it, but I’d like to remove the expectation for a method call, since I do not actually expect a method call at all, if the method is called, we will get an exception and this is
correct.
So the first test where we check if the reservation fails looks like this:
[TestMethod]
public
void
CannotExecutePaymentWhenReservationFails()
{
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value)).Returns(
false
);
var payment =
new
Payment(provider);
var result = payment.Execute(200);
Assert.IsFalse(result);
}
If you run this test (ctrl + r + t) it should process fine and you should see a green icon indicating that the test finished without any errors:
Next up we need to create the test that verifies that everything processes OK, so we need to create a test that checks if Execute returns true if Reserves does too. All we need to do here is add the line of code that we removed before that tells Simple.Mocking
that we are expecting a method call. The final test that we are going to make here will look like this if we add that expectation and change the reservation to return true:
[TestMethod]
public
void
CanExecutePaymentWhenReservationIsOk()
{
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() =>
provider.Reserve(Any<
decimal
>.Value))
.Returns(
true
);
Expect.MethodCall(() =>
provider.Execute(Any<
decimal
>.Value))
.Returns(
true
);
var payment =
new
Payment(provider);
var result = payment.Execute(200);
Assert.IsTrue(result);
}
If we run all the tests in the context (ctrl + r + a) it should gives us all green lights:
We could of course test if the Execution fails if both Reserve and Execute returns false, these are just similar test that you can add. As you can see Simple.Mocking is really powerful and of course you will need to test your real implementations, but before
you test your real implementations of your payment providers, you will want to know if your internal stuff is working.
There are actually systems that charge you a certain amount of money for each API call, these can get quite expensive if your build server runs through all tests all night. I hope you’ve seen how powerful Simple.Mocking is and how it can help you test faster
and test more. I read once that everything should be simplified to an interface, this would mean that anything can be mocked and anything can be tested in one way or another.
So in short what we’ve accomplished is that you now have a fake implementation of your interface that will allow you to test other things in your system that depends on certain values or methods being called on that implementation. Here is the entire code
that we’ve been looking over in this article:
using
Microsoft.VisualStudio.TestTools.UnitTesting;
using
Simple.Mocking;
namespace
Tests
{
[TestClass]
public
class
PaymentProviderTests
{
[TestMethod]
public
void
CannotExecutePaymentWhenReservationFails()
{
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value)).Returns(
false
);
var payment =
new
Payment(provider);
var result = payment.Execute(200);
Assert.IsFalse(result);
}
[TestMethod]
public
void
Can>var result = payment.Execute(200);
Assert.IsFalse(result);
}
ExecutePaymentWhenReservationIsOk()
{
var provider = Mock.Interface<IPaymentProvider>();
Expect.MethodCall(() => provider.Reserve(Any<
decimal
>.Value)).Returns(
true
);
Expect.MethodCall(() => provider.Execute(Any<
decimal
>.Value)).Returns(
true
);
var payment =
new
Payment(provider);
var result = payment.Execute(200);
Assert.IsTrue(result);
}
}
public
class
Payment
{
private
IPaymentProvider _provider;
public
Payment(IPaymentProvider provider)
{
_provider = provider;
}
public
bool
Execute(
decimal
amount)
{
if
(!_provider.Reserve(amount))
return
false
;
if
(!_provider.Execute(amount))
return
false
;
return
true
;
}
}
public
interface
IPaymentProvider
{
bool
Reserve(
decimal
amount);
bool
Execute(
decimal
amount);
}
}
This article about Mocking was originally posted by Filip Ekberg on
blog.filipekberg.se.