Reputation: 1940
I am trying to understand how to use Moq, however I am having some confusion about what Moq should be used for. My understanding is that mock framework are used for generating objects which would be difficult to create under normal circumstances. The examples I have seen of Moq however seem to not only create Moq object, but also provide methods for testing the objects - this would appear to remove the need for the usual Assert, etc methods we use for most unit tests.
Can somebody confirm whether I am correct in thinking that Moq replaces Assert, etc, or am I completely missing the point of Moq?
Upvotes: 4
Views: 1246
Reputation: 61795
+1 on the Q and the other A...
(restating Igor's very complete answer) A Mocking library is just a tool use within a test/spec - sometimes fulfilling the role of a stub or a mock.
Record/replay based mocking can often replace the role of Assert
s in your tests. This style has been deemphasized recently in RhinoMocks (I believe 4.0 was going to shunt it off to the side), and has been actively discouraged in Moq for quite some time. I believe this is what has got you asking the question.
You should be optimising your tests to:
The final point here is the critical one - you want one bit where you're doing Checks, and it should be the final Assert one. Sometimes this can mean that you can even end up doing a Setup
a call in Moq in the Arrange/Context phase and then Verify that it got used in the Assert phase with code that looks like duplication.
Upvotes: 2
Reputation: 76500
A mocking framework like Moq does not completely replace the testing framework's Assert
. sometimes it does, sometimes it doesn't.
Let's first distinguish between mocks and stubs. Stubs are used purely for isolation and to inject some sort of controlled behaviour into system under test (SUT).
Mocks are a superset of stubs and are able to verify whether or not something was called on a mock. In Moq, an invocation of Verify()
makes stub a mock with respect to that method. Calling VerifyAll()
makes all methods that were set up mocks.
The recommended approach is that you should have no more than one mock in your test. In that sense, it is similar to Assert
- that you shouldn't be verifying more than one thing in a test.
Coming back to the original question. If you are performing state testing, than you would use zero or more stubs and one assert. If you are doing interaction testing, than you would use zero or more stubs and one mock. Below is an example where it might be appropriate to use both mocks and asserts to test the same service.
public interface IAccountRepository {
decimal GetBalance(int accountId);
void SetBalance(int accountId, decimal funds);
}
public class DepositTransaction {
IAccountRepository m_repo;
public DepositTransaction(IAccountRepository repo) {
m_repo = repo;
}
public decimal DepositedFunds {get; private set;};
void Deposit(int accountId, decimal funds) {
decimal balance = m_repo.GetBalance(accountId);
balance += funds;
m_repo.SetBalance(balance);
DepositedFunds += funds;
}
}
public class DepositTest {
[TestMethod]
void DepositShouldSetBalance() {
var accountMock = new Mock<IAccountRepository>();
accountMock.Setup(a=>a.GetBalance(1)).Returns(100); //this is a stub with respect to GetBalance
var transation = new DepositTransaction(accountMock.Object);
transation.Deposit(1, 20);
accountMock.Verify(a=>a.SetBalance(1, 120)); //this is a mock with respect to SetBalance
}
[TestMethod]
void DepositShouldIncrementDepositedFunds() {
var accountMock = new Mock<IAccountRepository>();
accountMock.Setup(a=>a.GetBalance(1)).Returns(100); //this is a stub with respect to GetBalance
var transation = new DepositTransaction(accountMock.Object);
transation.Deposit(1, 20);
transation.Deposit(1, 30);
Assert.AreEqual(50, transaction.DepositedFunds);
}
}
Upvotes: 4