简体   繁体   中英

Does Moq replace standard VS 'Assert' testing?

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?

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);

  }
}

+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:

  • Be readable for you, maintenance programmers, and pretty much anyone that's ever going to have to debug or extract info from your test code
  • Assert as few things as possible
  • Not overlap with other tests
  • Not be brittle - tests shouldn't be breaking for incidental reasons when you change something only tangentially related to your test. In the context of Moqing and mocking, this means veering away from Strict mocks in most cases
  • Do as little work as possible to prove their point
  • Have clear separation of Arrange/Context, Act and Assert sections

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM