Pergunta

Context

I'm currently developing an application following the Clean Architecture principles (at least I'm trying really hard to follow these).

All my Dependency Injections are done manually, without any Framework.

One of my Use Case consists of the user being able to answer to a question he was asked.

  • If he/she is wrong, nothing happens, he can try again

  • If he/she is right, a list of things happens :

    • I get back his/her current session, and modify the state of that session. (Update session step - DB read)

    • I get back a contact record from the database (Get Contact step - DB read)

    • I send a mail into an in-app mailbox with this contact information (basically it's a database insert of a message) (Send Mail step - DB write)

    • I save the updated session (Save session step - DB write)

    • I push an event into a custom Message Queue (Programm event step - Queue write)

Issue

All of the work described above are the steps I need to go through if the user answer to this question; it's kind of an Application Logic. For that reason, I created a specific AnswerQuestionUseCase which do all of this.

Because of all these databases interactions, I now have 5 dependencies injected into my Use Case, and I'm starting to think this is a code smell of bad design. The unit test of this class is ugly, not quite readable with all these mocks.

Solution ?

I searched a bit how to deal with this issue, and I found that Function Composition might be a good way to avoid so many dependencies, but I've found that if a go that way, all of the Application Logic would go outside of my Use Case, deported into the presenter maybe.

I could also break my Use Case into smaller Use Cases, but that just hide the issue, pushing the dependencies elsewhere.

I thought the Use Case was a block of Application Logic which you couldn't break apart for a specific use case of your app.

Is my understanding of what should be a Use Case any good ? How would you deal with that many dependencies ? How would you use Composition over DI to avoid so many mocks inside the unit test of this case ?

Foi útil?

Solução

The simplest answer I know of is to separate the bits that consume the data from the bits that provide the data.

The bit that knows about the application specific business rules is just an in memory state machine -- aka an "object" -- with a data interface.

Separate from that is the protocol, the bit of logic that understands how to move the data from one place to another. This is the bit of code that coordinates the flow of data between the different dependencies. In other words, this code knows how to route the data from one place to another, but doesn't usually need to inspect the data.

So you test the application specific business rules by instantiating the object in your test, and passing data to it directly.

You test the protocol by using test doubles.

In some cases, the protocol can be broken down into logical units that don't involve all of the dependencies. In that case, you can write tests that focus on the smaller units, with tests that focus on the coordination between a subset of the dependencies, rather than all of them.

You might find these talks helpful:

Licenciado em: CC-BY-SA com atribuição
scroll top