79700070

Date: 2025-07-13 15:48:35
Score: 1.5
Natty:
Report link

Can you tell me how to test and design the frontend part that calls the backend with error handling.

The underlying assumptions of test driven development:

When our goal requires both API calls and complicated logic, a common approach is to separate the two.

Gary Bernhardt's Boundaries talk might be a good starting point.


Consider:

    async execute(requestModel: BookAHousingRequestModel): Promise<void> {
        let responseModel: BookAHousingResponseModel;

        const user: User | undefined = this.authenticationGateway.getAuthenticatedUser();

        if(!user) {
            responseModel = this.authenticationObligatoire()
        } else {
            const housing: Housing | undefined = await this.housingGateway.findOneById(requestModel.housingId);
            responseModel = this.responseDeHousing( requestModel, housing );
        }

        this.presenter.present(responseModel)
    }

Assuming that BookAHousingRequestModel and Housing are values (facades that represent information in local data structures), then writing tests for the logic that computes the response model that will be forwarded to the presenter is relatively straight forward.

(Note: there's some amount of tension, because TDD literature tends to emphasize "write the tests first", and how could we possibly know to write tests that would produce these methods before we start? You'll have to discover your own answer to that; mine is that we're allowed to know what we are doing.)

So we've re-arranged the design so that all of the complicated error handling can be tested, but what about the method that remains; after all, there's still a branch in it...?

By far, the easiest approach is verify it's correctness by other methods (ie: code review) - after all, this code is relatively straight forward. It's not immediately obvious to me that the extra work that would need to be done to create automated tests for it will pay for itself (how many mistakes do you expect that test to catch, given the simplicity here)?

But maybe this problem is standing in for something more complicated; or we are in an environment where code coverage is King. Then what?

What we've got here is a sort of protocol, where we are making choices about what methods to call. And a way to test that is to lift the protocol into a separate object which is tested by providing implementations of the methods that can be controlled from the tests.

One way that you could do this is to introduce more seams (See Working Effectively with Legacy Code, chapter 4) - after all, our processing of errors into a response model doesn't really care about where the information comes from, so we could try something like....

    constructor(
        private responseModels: ResponseModels, 
        private presenter: BookAHousingOutputPort, 
        private authenticationGateway: AuthenticationGateway,
        private housingGateway: HousingGateway,
        private dateTimeProvider: DateTimeProvider) {}

    async execute(requestModel: BookAHousingRequestModel): Promise<void> {
        let responseModel: BookAHousingResponseModel;

        const user: User | undefined = this.authenticationGateway.getAuthenticatedUser();

        if(!user) {
            responseModel = this.responseModels.authenticationObligatoire()
        } else {
            const housing: Housing | undefined = await this.housingGateway.findOneById(requestModel.housingId);
            responseModel = this.responseModels.responseDeHousing( requestModel, housing );
        }

        this.presenter.present(responseModel)
    }

The point here being that you can "mock" the response models implementation, passing in a substitute implementation whose job is to keep track of which method was called with which arguments (aka a "spy") and write tests to ensure that the correct methods are called depending on what answers you get from the authenticationGateway.

(The TDD community tends to prefer composition to inheritance these days, so you are more likely to see this design than one with a bunch of abstract methods that are overridden in the tests; but either approach can be made to work).

Reasons:
  • Blacklisted phrase (1.5): tell me how to
  • RegEx Blacklisted phrase (2.5): Can you tell me how
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Starts with a question (0.5): Can you
  • High reputation (-2):
Posted by: VoiceOfUnreason