# E2E tests, Integrated tests vs Collaboration and Contract tests

## 测试金字塔

1. Integration Tests would be a abstract idea. The tests that give you confidence that your systems will work together in production.
2. Integrated Test is the current default implementation of Integration Test and a scam.
3. Collaboration Test is an implementation of Integration Test and the approach you recommend.
Intergration <|-- Intergrated       :scam
Intergration <|-- Collaboration     :recommend


By putting all the components together and running them in a single test, you’re throwing tests at the system, hoping to cover the whole thing.

I believe that this results from how utterly distracting integrated tests become over time: riddled with duplicated, mostly-irrelevant details.

These details assault our senses and beat our conscious minds into submission. Our eyes glaze over. Before long, we stop paying attention. Over time it becomes easier, not harder, to make a mistake.

Contract = Semantics + Syntax(Compile check will do this)

I, programmer, write contract tests in order to avoid end-to-end tests. It would satisfy me to replace my end-to-end tests with collaboration and contract tests over time.

My System 作者的思路：

Rather than throw paint at the wall, let me describe what I do, which corresponds to painting the corners of the wall with a brush.

First, I describe the key properties of collaboration and contract tests:

• A stub in a collaboration test corresponds to the expected result of an assertion in a contract test.
• An expectation in a collaboration test corresponds to the action of a contract test.
• These correspondences apply equally well in both directions.
stub ~= assert equals expected result
expectation ~= action


From this, we can extract some helpful rules:

• When I write a stub in a collaboration test, then I remind myself to also write a contract test where the stubbed return value becomes the expected result of the contract test.
• When I write a contract test with assert_equals() in it, then I can safely stub that method to return that value in a collaboration test. Moreover, I should probably try to imagine a collaboration test for the client that stubs that method to return that value so as to document what happens in that case. Maybe I need it; maybe I don’t.
• When a collaboration test expects a method (with certain parameters), then I remind myself to also write a contract test that describes what happens when we invoke that method with those parameters. Any module that implements that method must behave accordingly.
• When I write a contract test with the action foo(a, b, c) in it, then I can safely write a collaboration test that expects (“mocks”) foo(a, b, c).

## Simulating Failure in Collaboration Tests

Limiting beliefs and unstated assumptions interfere with our performance.

Crash Test Dummy pattern: implementing the interface with methods that intentionally raise errors. 崩溃测试模拟模式：实现那个故意产生错误的方法的接口

Knowing where to find experienced people who can answer your questions doesn’t only help you get answers to your questions, but more importantly, it frees you to focus on the details and allow yourself to struggle, but of which are essential for effective learning.

You don’t have to worry both about how to do the thing and whether you’re doing “the right” thing. You can get something working, then take a breath, then ask for advice. We all need help like this from time to time, so it helps to have a safe place to ask these kinds of questions where someone with experience can answer them.

Since integrated tests are still a scam, you might prefer to use Collaboration and Contract Tests to check the integration between the Controller and the Repository.

## Test Doubles 测试替身

Typically, when you think you want to mock an entity, first try mocking the repository from whence it came.

Services, you can mock with impunity. In fact, the only time not to mock a service is when you’re testing the service.

Put another way, I lean on interaction-based testing to verify how my object talks to its collaborators; but I lean on state-based testing to verify how well that object listens.

Never mock values, sometimes mock entities, but mock services freely.

When I want to rescue legacy code, I reach for Mockito. When I want to design for new features, I reach for JMock.

## Verification Tests

• chadojs is a mocking library for nodejs which reduces the need for integration tests. Instead of integration tests it supports writing verification tests.

The problem with mocks is, that the tests still pass, although the real objects might not work together any more.

There are two ways how you can deal with that.

• Avoid mocks and use the real object instead. ==> not always possible or desired.
• Assure that mocks are in sync with the real object. ==> Whenever you mock a unit, you verify that the real object can behave like the mock.