Why is it so bad to mock classes?

前端 未结 9 1861
一向
一向 2020-12-07 17:57

I recently discussed with a colleague about mocking. He said that mocking classes is very bad and should not be done, only in few cases.

He says that only interfaces

相关标签:
9条回答
  • 2020-12-07 18:18

    IMHO, what your colleague means is that you should program to an interface, not an implementation. If you find yourself mocking classes too often, it's a sign you broke the previous principle when designing your architecture.

    0 讨论(0)
  • 2020-12-07 18:19

    Edit: Since you have clarified that your colleague meant mock class is bad but mock interface is not, the answer below is outdated. You should refer to this answer.

    I am talking about mock and stub as defined by Martin Fowler, and I assume that's what your colleague meant, too.

    Mocking is bad because it can lead to overspecification of tests. Use stub if possible and avoid mock.

    Here's the diff between mock and stub (from the above article):

    We can then use state verification on the stub like this.

    class OrderStateTester...
      public void testOrderSendsMailIfUnfilled() {
        Order order = new Order(TALISKER, 51);
        MailServiceStub mailer = new MailServiceStub();
        order.setMailer(mailer);
        order.fill(warehouse);
        assertEquals(1, mailer.numberSent());
      }
    

    Of course this is a very simple test - only that a message has been sent. We've not tested it was send to the right person, or with the right contents, but it will do to illustrate the point.

    Using mocks this test would look quite different.

    class OrderInteractionTester...
      public void testOrderSendsMailIfUnfilled() {
        Order order = new Order(TALISKER, 51);
        Mock warehouse = mock(Warehouse.class);
        Mock mailer = mock(MailService.class);
        order.setMailer((MailService) mailer.proxy());
    
        mailer.expects(once()).method("send");
        warehouse.expects(once()).method("hasInventory")
          .withAnyArguments()
          .will(returnValue(false));
    
        order.fill((Warehouse) warehouse.proxy());
      }
    }
    

    In order to use state verification on the stub, I need to make some extra methods on the >stub to help with verification. As a result the stub implements MailService but adds extra >test methods.

    0 讨论(0)
  • 2020-12-07 18:25

    Mocking classes (in contrast to mocking interfaces) is bad because the mock still has a real class in the background, it is inherited from, and it is possible that real implementation is executed during the test.

    When you mock (or stub or whatever) an interface, there is no risk of having code executed you actually wanted to mock.

    Mocking classes also forces you to make everything, that could possibly be mocked, to be virtual, which is very intrusive and could lead to bad class design.

    If you want to decouple classes, they should not know each other, this is the reason why it makes sense to mock (or stub or whatever) one of them. So implementing against interfaces is recommended anyway, but this is mentioned here by others enough.

    0 讨论(0)
提交回复
热议问题