DEV Community

loading...

Discussion on: TDD in Angular - Dependency Injection and Mocking

qarunqb profile image
Bearded JavaScripter Author • Edited

Also, with respect to one of your previous questions, yes it is possible to build an entire Angular app using TDD, it helps to promote a nice structure in your application.

However, aiming for 100% test coverage is difficult for pretty much any codebase, so I would personally advise testing Business Logic and core requirements first and then the rest of the tests can come after.

Keep in mind that some business logic could be UI related as well, so that's where Cypress e2e tests would come in, not necessary unit tests

Thread Thread
stealthmusic profile image
Jan Wedel

When you say backend, do you mean your services or your actual back end server?

By backend, I mean the backend server. By backend model, I mean a typescript class/interface that maps to the data model from the backend.

By component model, I mean a data structure that holds all the state/fields of the component which is data binded from the parent component and represents the UI better.

So in your example, User would be a backend model. We don't have a backend-for-frontend architecture but multiple backends. For example, one businiess entitiy that references a user by ID. Then we need to load the appropriate user as well to display it name in the ui.

The frontend model e.g. contains selected chip options for a autocompletable chip list rather that an array of User entites etc.

With respect to the second point, I'm not sure what you mean, but ReactiveForms in Angular are made with TDD first in mind since they are created in the TypeScript before the HTML is initialized.

I know about reactive forms but haven't tried them. Maybe I should have a look on them. We use template driven forms but we don't use the HTML submit. Instead, we call the backend with a POST/PUT when the form is "saved". Then, we need some cross-field validation logic that also can/should be unit tested to cover all the edge cases.

I hope that clears my comment up a bit.

However, aiming for 100% test coverage is difficult for pretty much any codebase, so I would personally advise testing Business Logic and core requirements first and then the rest of the tests can come after.

Noone should pointlessly aim for 100% coverage. Why I really meant is writing tests before writing any line of component code, including template and code.

When I tried that, I really didn't know how to start. I first needed to play around with material components, learn how they work, what there interfaces are... So I couldn't really write a Cypress test before because I din't know what HTML element I should select for expectations...

Thread Thread
qarunqb profile image
Bearded JavaScripter Author

Thanks a lot for the clarifications.

With respect to the forms, it's really up to the developers on how they wanna handle the validation. Once you decide that, the unit tests will follow where your validation is.

So for example:

<form action = '/create-user' method = 'POST'>
...
</form>

There really isn't much unit testing that could be done on the front end in terms of validation. An Angular HttpInterceptor can technically still catch the request before it goes off to the server, so it can grab the body and perform validation checks there, but you can also do the validation checks on the server and return the appropriate response based on the form value.

With respect to a ReactiveForms declaration inside a component as follows:

form: FormGroup;

constructor(private fb: FormBuilder) {
  this.form = this.fb.group({
    name: this.fb.control('', Validators.required),
    email: this.fb.control('', [Validators.required, Validators.email]) 
  });
}

This form can be unit tested and validated entirely on the client side to ease Validation on the server side. You can find many of the Validators here. And you can even stitch together custom validators to consider weird cases as well. Angular also comes with Sanitization for user input as well, though I have to do some more research on it.

Thread Thread
layzee profile image
Lars Gyrup Brink Nielsen • Edited

@stealthmusic

When I tried that, I really didn't know how to start. I first needed to play around with material components, learn how they work, what there interfaces are... So I couldn't really write a Cypress test before because I din't know what HTML element I should select for expectations...

This is one of the issues that component harnesses address. You'd have to implement a HarnessEnvironment for Cypress though.

mapping a backend model (which is returned by an angular service) to a component model that contains all and only the information in appropriate data format that it can be used in templates.

There are many ways to approach this. I prefer creating input properties with data types that are the most convenient for presentational components and then doing mapping either in container components or services used by container components.

We can then easily test the mapping in isolated unit tests and there's less business logic in our presentational components.