Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> 3. Allows you to assert expectations on it.

I think this is the crux that separates Fowler's mock, spy, and stub: Who places what expectations.

Fowler's mock is about testing behavioral interaction with the test double. In Fowler's example, the mock is given the expectations about what APIs will be used (warehouseMock.expects()) then those expectations are later asserted (warehouseMock.Verify()).

Behavioral interaction encodes some of the implementation detail. It asserts that certain calls must be made, possibly with certain parameters, and possibly in a certain order. The danger is that it is somewhat implementation specific. A refactoring that keeps the input/output stable but achieves the goal through different means must still update the tests, which is generally a red flag.

This is what my original statement referred to, the interaction verification. Generally the expectations are encoded in the mock itself for ergonomics sake, but it's technically possible to do the interaction testing without putting it in the mock. Regardless of exactly where the assertion logic goes, if the test double is testing its interactions then it is a Fowler mock.

(As an example: An anti-pattern I've seen in Python mocks is asserting that every mocked object function call happens. The tests end up being basically a simplified version of the original code and logic flaws in the code can be copied over to the tests because they're basically written as a pseudo stack trace of the test case.)

In contrast, a stub is not asserting any interaction behavior. In fact it asserts nothing and lets the test logic itself assert expectations by calling the API. ie:

> 3. Allows you to make assertions on that change in state. (e.g. fetch record and assert it has changed)

How is that change asserted?

A Fowler stub would be:

> myService = service.New(testDB.New()) > myService.write("myKey", 42) > assert(myService.read("myKey") == 42)

A Fowler mock would be:

> testDB = testDB.New() > testDB.Expect(write, "myKey", 42) > myService = service.New(testDB) > myService.write("myKey", 42) > testDB.Verify()

These concepts seem distinct enough to make mock a simple.

Fowler's spy seems to sit half-way between mock and stub: It doesn't assert detailed interaction expectations, but it does check some of the internals. A spy is open-ended, you can write any sort of validation logic, whereas a mock is specifically about how it is used.

I have used spys in Go basically whenever I need to verify side effect behavior that is not attainable via the main API.

By Fowler's definition, nocks are a niche test double and I suspect that what many folks would call a mock are not technically a mock.



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: