Because testing is an important aspect of software design. We expect to design our tests and our application code in harmony and to give both the design attention that they deserve. This does not mean that we lose a lot of time imagining abstractions that are unnecessary. To the contrary, we save time because our test tooling enables simple / comprehensive testing patterns. It also runs quickly because it doesn't test database access for every service that interacts with an object-graph connected to a repository.
The repositories will be tested fully with integration tests that have their own fixture class (will discuss later) and will directly interact with the database.
Our fixtures and our test doubles exist for a bounded context. They are not used for an entire application. Therefore they're 'tight' and to-the-point.
The test doubles use easy-to-comprehend language that help to turn the tests from complex setup and implementation into descriptions of how the system under test works.
You can build the fixtures and test doubles to use patterns that you find useful. I enjoy the pattern of being able to override values for text fixtures. Notice that in the test I explicitly type out the DeliveryId::fromString('delivery id')
bit repeatedly. I like this because I feel like it makes the test more comprehensible. You may prefer to bind it to a variable, or because a default value is available within the fixture factory, you can just have your tests directly use 'some default delivery id' instead. Your call.
The test doubles can be much more than just in-memory versions of repositories. They can be a nice place to put convenient assertions and other behavior that assists in making tests easier to develop, run faster, and easier to read.