hamvocke / spring-testing

A Spring Boot application with lots of test examples
https://www.martinfowler.com/articles/practical-test-pyramid.html
1.09k stars 430 forks source link

Include authentication. #20

Closed ghost closed 8 months ago

ghost commented 2 years ago

Would be nice to have demo of how to integration test controllers when authentication is in play.

hamvocke commented 2 years ago

Yes, I see how authentication is a common problem many devs are wrestling with. I thought about adding something about auth (both, authentication and authorization) in the past but decided that this is not the right place. Auth is an important aspect but the purpose of this repo (and its corresponding blog post) is to explore different categories of tests first and foremost, while being agnostic about the problem domain of your application.

The problem is that talking about authentication is opening a huge can of worms.

For now, I don't want to go there with this repo and this blog post. However, I see how this is a legitimate need and I might come up with something in the future if I can find the time.

To address your immediate issue (and maybe this helps others who might stumble across this issue in the future):

Testing authentication is a matter of picking the right layer for your tests and asserting that you see the right behavior. A controller might return a 403 for a logged out user but a 200 for a logged in user. The response body might change. Your code might utilize Spring Security's automagic to handle authentication, or it might be much more explicit by passing a User kind of object to those methods that do something for a given user.

For all things regarding your controllers, @WithMockUser is a good start. It allows you to act on behalf of a mocked user as part of your integration test (whether that test's a WebMvcTest that only spins up your controller layer or whether that test's a full-blown SpringBootTest doesn't matter.

For your services and repositories, you might not even need this kind of annotation magic if you make your method signatures more explicit by passing a Principal (or your own representation of a User) object into your functions that rely on that information to perform any logic. This would allow you to simply unit test that function by passing in User/Principle objects with the right (or wrong) permissions, etc.