ong post.. I will try to answer it my way (and then you can ask q if it doesnt satisfy you) If a controller is using Request/Validation then yes I would test to make sure validation passes/fails as appropriate for main things ie user tries to register an email thats already been registered or your own custom password rules.. (no point in testing other stuff as thats laravel built in and for sure would have been tested by that) generally speaking if you are creating more than one tests for a controller, if you haev already tested something in one controller no need to test/assert it again.. you also mock stuff like services or repository in a controller and you have dedicated repositoryTest or ServiceTest you should also test any methods you create in Models.
A general (long) question on TDD and test organization
So lets say we have a resource called 'Organization'. The application has 3 basic roles: admin, manager, staff. The roles are not really important, just showing that we need a policy for who can change what in the Organization. We have the following classes that support working with an organization via an API:
- Organization (model)
- OrganizationController
- OrganizationPolicy
- OrganizationRepository
- OrganizationValidator
- OrganizationService (maybe)
Writing up unit tests for the Policy and Validator are fairly straightforward, but it brings me to my first question:
1. When testing policy's and validation rules, do you test every possible failure case along with every possible success case? If Organization has some ingrained business logic in regards to what fields can be updated by what roles, it would seem that this could get unwieldy fast. Same goes with complex validation requirements. Do you test every possible way validation could fail, ensuring it does?
Next lets look at the repository. The repository relies on the validator which we already tested.
2. Do we still test that the repository uses the proper validation logic for all possible cases? Or do we just trust our validation tests and make sure the repository is creating records in the DB?
My hunch is that we just mock the validator and make sure the proper validation method is called for each repository method.
Which brings us to the controller. This seems like the ideal dividing line for unit/functional testing. I am feeling that controller tests should really be "integration" or "functional" tests (depending on how you label them). Only mock what you absolutely need to. But it still brings me to the question:
3. How many possible failure states should we test at the "integration/functional" level? Both when it comes to the policy and the validation?
When you start combining all the possible ways to test failure cases, it can feel like its growing exponentially. Do we test every role? Do we test every possible combination of fields for validation?
Lastly would be the service if one is needed. It most likely has dependencies on one or more repositories and other services.
4. Do we just mock the services dependencies and cover the service with unit tests? Or should this be part of our integration test layer as well?
So I guess what I am trying to get at is: how can the typical laravel application structure inform our layers of testing? I know hard and fast rules are rarely appropriate, but I feel like a good set of guidelines would make cleaning up our tests and introducing new devs to testing much easier.
Maybe something like this:
Unit: Policy, Validation, Repository
Integration: Services
Functional: Controllers
Am I making any sense here? Thanks.
tl;dr: 1) How to organize levels of testing based on common laravel application structure and classes? 2) How deeply do you test failure cases for validation and policies?
Please or to participate in this conversation.