Spring Boot Testing Basics: How to Unit Test & Integration Test REST Controllers
Vložit
- čas přidán 7. 09. 2024
- In this tutorial, I want to discuss some basics of testing a rest controller in a Spring Boot application. This came up because of a tweet I sent out recently asking developers to stop calling a certain test a unit test. The reason I said this is because whenever you start involving Spring and the whole request & response lifecycle its no longer a unit test. In this demo, I will create a new Spring Boot application, create a simple rest controller and then show you how I would Unit & Integration test that controller. If anything this is just meant to spark a discussion so I would love to hear your thoughts on the subject.
When you have completed this tutorial you should understand:
✅ Create a new Spring Boot Application
✅ Create a new Spring Boot Rest Controller
✅ Create a Unit Test
✅ Create an Integration Test
✅ Run a basic test in a Spring Boot Application
✅ How to use JUnit 5 in a Spring Boot Integration Test
🔗Resources & Links mentioned in this video:
Source Code: github.com/dan...
Martin Fowler Unit Test: martinfowler.c...
👋🏻Connect with me:
Website: www.danvega.dev
Twitter: / therealdanvega
Github: github.com/dan...
Instagram: / thedanvega
LinkedIn: / danvega
Coffee & Code: www.danvega/de...
SUBSCRIBE TO MY CHANNEL: bit.ly/2re4GH0 ❤️
What is your definition of a Unit & Integration Test?
I agree with your definition of Unit and Integration Test. For Controller and Data layer, spring boot gives nice mock to test actual annotation and spin up minimal context. Because those layers we are not keeping much business logic.
I really never understood why using Unit Test on controllers. For each request a controller usually does a lot of steps like deserialize, validate, translate exceptions, etc its almost impossible do cover that on Unit Tests. IMHO, Unit Tests on controller (http layer) is just to verify business logic has been called and i can't see relevant value on it. Maybe i'm wrong but I really believe it's better build just Integration Tests for HTTP layer.
@@pvrsouza I agree with you. Usually in projects I work with, Controllers are only tested in Integration tests. and kinda solves coverage so
There is no hard line between a Unit Test and an Integration Test. If you wanted a pure unit test then you would have to mock every external dependency, which would mean even mocking "String" objects. SUddenly It gets completely absurd. I have been in projects where they have written tests that are about 20 lines long, and that have tested exactly ONE line of code. The value of tests like this are next to ZERO. In my opinion unit tests are generally useless, unless you need to test complex algorithms or things like utils methods like DateUtils and that kind of thing. As soon as you start mocking too much you get tests which have no value. Integration Tests are much better because they more closely resemble Use Cases. As long as the performance/speed of these tests is good (TIP: use in memory databases!!!!! ), then you should focus on them over unit tests. Writing a test that goes from the RestController to the DB is excellent. It perfectly captures a Use Case. As long as the performance is fine..... do it like that!!!!!
Isnt the @Test a spring notation? Refering to the start of the video where you said spring wasnt involved yet. Just out of curiosity so I know if I understand spring well enough in the basics.
I literally spent 5 hours trying to achieve this. At 2 am I found your video. Thank you so much!
Glad it helped!
Your definition is right. Unit - Single entity.
Integration - How it works with entire system.
Imagine if you have missed @RestController annotation, unit will pass but int fails.
WoW..!! Dan!!! Thanks for sharing an amazing tutorials and good explanation. It is 4:00am here. Thanks to you, my searching ends here.
100% agree with your thoughts about unit testing and integration testing
I could use this AutoConfigureMockMvc testing with your other Testcontainers you gave us in another video. Thanks Dan !
It’s 5:17 am and I found this. Thanks for ur video
This is the best video about testing. Watched so many but yours let everything clear! (im junior)
Wow, thank you! That is a great compliment. Is there anything else in testing you would like me to cover? I should have a video on Spring Data Slice Testing coming out this week.
@@DanVega Well usually every video has details of how to create a rest controller or other types of controllers. I get that, but when you apply for a junior job, they assume you already know testing. Thats not the case.
I have a controller that returns a DTO with this format: {"idUser":0,"email":null,"firstName":null,"lastName":null,"loans":null}(loans is a list)
Well i have no idea of how to test it. Should i recreate the entire method in the test class? I dont think so because in that case whats the difference with just using postman.
Maybe this sound dumb to you, but ive started to code 6 months ago, and right now im applying for spring junior dev (fintech). They want me to know: ORM, Spring Boot, SQL, Hibernate, GitHub, Maven, testing and logs.
I think 1 minute at the end of the explanation quickly showing how to test it would be great, but i get it, thats a low of added work.
Dan Vega It would be great if you can do basic spring boot testing videos for junior automation testers/developers etc.
Would be grateful
I may be wrong about this it's been a while since I've "looked under the hood" in spring, but doesn't the spring framework, as soon as it sees the at test annotation, create its own mock dependency. I'm thinking that I remember it marks the entire environment so that it can run the tests.
Also one key point about integration tests just because a test _includes_ integration (via stubs,mocks, etc) that doesn't make it an integration test. When you write a unit test that contains mock dependencies on neighboring classes, you're not writing assertions to check that those integrations are working as intended, as you would in an integration test. in fact, with mocks the integration isn't even there. The entire point of frameworks like makito is to take the 'integration' factor out of the dependencies.
In summary, the point I'm trying to make is that while unit tests may contain dependencies, and occasionally with third-party dependencies, may even contain integration, integration tests actually test said integration and fail if it doesn't behave as expected. Just my two cents. Have a great day.
Btw, have I commented on this video before? This whole thing is feeling eerily deja Vu to me...
Thank you ! I had an argument the other day with one of the devs about unit testing in go lang . spinning up an entire http server to just do a controller test is stupid that's an integration test not unit .
As I said above, it doesn't depend on what you're running in a test it depends on what you're testing. You can start up the whole damn application and call every single method in your unit, but if you're assert methods are only testing the functionality inside your unit, in this functionality is not being changed by anything else that is happening, it is still just a unit test. One more time, just for clarity, to be an integration test, it has to __test__ that the units are integrating as expected, and fail if they are not. Otherwise it is just a unit test. Simple as that.
If we're going to start naming tests based on what they include, then by this logic, every test is a unit test because they all include units...
I have spent a whole night on this thing!
@@natetolbert3671 But my teammates are checking the be rest controller just as an normal classs i.e. calling method and asserting the return value without worrying about checking get/post mapping. Should I go with mockmvc or just normally test like others have done.
I solved the problem " java.lang.IllegalStateException: Failed to load ApplicationContext" by repacing 2 annotations of the test class with @SpringBootTest
and @AutoConfigureMockMvc.
I'm new to Java and I have no idea why this works/ how it's different, but this worked for me too lol.
Thank you bro it's worked well :)
Quick and fast way to understand difference and learn 👍
Nice and clean explanation, thank you!
Glad it was helpful!
thank you for this! I’m supposed to be writing a unit test before I move on to integration testing and it seems like I jumped the gun
That is very interesting, could you make some video on how to test services and repository ?
Plain and simple. Thank you! Awesome if you could make a more in depth video about this.
Thanks a millioooon for the great explanation and illustration
CLEVELAND! Go Browns! :) This is a great vid. I went to We Can Code IT and we learned this, but it helps refresh my learning of Testing.
Thank so easy to understand would be nice if you advance this topic on the more complicated methods as well
What an absolute beautiful video man!
I just found our videos 2 weeks ago(Love them) Would it be possible to show how to create proper JUNITs over the Spring Repo Layer. A lot of mocking and i get confused
Great video, couldn't figure out the Integration Testing, thanks!
as far as i know unit tests are designed to test application logic, so if you unit tests a controller that means you have application logic inside a controller which as far as i know , is a big no no.
Pretty clear.. can extend the video series for writing integration for Mapper, Converter, like all different models..? That will clear all the stuff..!
question on integration tests - Whats the best practice if this endpoint need to fetch data from database, do we spin up in memory like H2 or hit the db by running these tests in Dev??
thanks for sharing this kind of content!
Love this video BUT love the shirt even better! Go Browns! From a fellow Ohioan to another thanks for the videos!
OH- Thank you Chad! I actually made that shirt myself. I have a bunch of Browns shirts so I will try working them in.
It feels like the distinction between unit and int tests is fuzzy. Because there're different levels of how many levels of your system you can include in your tests. The easiest scenario, when you test just one component, with its integrations with other components replaced by mocks, is unit testing, that's pretty much clear.
For integration tests, you can test any level of integration, from the simplest, like just plugging the web framework as in your example, and still mocking stuff like database and calls to other microservices, up to spinning up your entire ecosystem, with all layers included, e.g. locally via docker and test containers. Are these types of testing all integration tests? What I've got is that it's still a matter of debate, some people consider the first type (like in your example) to still be unit testing. And I guess the reason for the debate is that it kinda has features of both.
Cool to make the first step by step part (Request builder request...., MvcResul result...., assertEquals(...) with this is much more understandable the code after mvc.perform....
It does not matter what you think of the component or unit , it doesn't matter if you don't count it as valuable.
Integration tests - tests for the stand alone components interaction between their public interfaces.
Unit tests - are tests for the smallest testable parts of the application.
That's it.
Thank you for your tuto, very good work
Really nice one. It helps in understanding the between unit test and integration test. can you make more videos on integration test. Also looking for test using Mockito
Thank you Dan for this content. Would you please share your experience with more advanced examples of integration tests using DdUnit ?
this is beautiful, thank you
Thank you so much!
you missed a thing at 10:50 , wheren webmvctest annotation does not create bean for @component , service and reporsitory
Hello, I don't have the get() method in 14:55. When I click "Import static method" it gives me lots of methods to choose.
I often am confused on where this is coming from as well. Here is the static import for that
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@DanVega thank you so much!
Grear Dan! 😊
Gracias mi pana, muy bien explicado un abrazo!
Where did you get your shirt? Love it!
I actually made that myself when I briefly got into the t-shirt side hustle game 🤣
My assert equals fails because of the URI returns empty with body = null. When I do a get command from the URI it does show me the string I would want to compare but it doesn’t work for the assertEquals
Hi Sir why do we need to add HelloController.class inside the @WebMvcTest? is this annotation not capable of doing component scan aromatically thanks ?
You don't have to but if you to avoid scanning and be specific it could help performance in a larger app
Thank you
Thank you for watching!
Thank you so much sir :)
Hey could you show us how to test REST mappings that must pass through Spring security configuration?
thanku man i love u
Happy to help
Hi Dan, great video. Is it fair to assume that these kinds of integration tests involving the Spring components ie. @WebMvcTest are excessive? I'm sure the Spring devs test their own MVC-related components, so aren't we just testing something they're already testing themselves before making releases of their libraries? If my assumption is correct here, then is the unit test you made at first in this video all that is needed to ensure the code that YOU wrote is working properly?
I'm still very new to TDD in general and I'm trying to wrap my head around some of these scenarios and would love your input here.
Thanks! -Matt
no because the WebMvc test is testing the request parameters you are defining in the rest controller method. This logic cannot be covered by a vanilla test.
If you test the whole Spring application, with the *@SpringBootTest* , without mocking any beans, is it called an integration test, or acceptance test?
wow thanks
You're welcome
Thanks a lot.
But how can do an integration test when my micro service use other 2 micro service to get me a response ? I have to mock the response from the others micro services ? or what , I have a huge doubt about it
Is this integration test or unit test? Should you split both on their own folders or something?
Do you have a video like for testing this but also using a service and a repository to do stuff with a db?
nice :)
Thanks!
What is the difference between unit test and component test?
I always get "java.lang.IllegalStateException: Failed to load ApplicationContext" :/
maybe you need to add your base package to the @SpringBootApplication(scanBasePackages = "your.base.package") int the UnitVsIntApplication class.
I solved that problem by repacing 2 annotations of the test class with @SpringBootTest
and @AutoConfigureMockMvc.
In what cases in tests does it make sense to use a web server, and not MockMvc?
Thank you for the question. When you want to do a true end to end test and simulate a production like environment I would use a web server.
@@DanVega thanks a lot
thanks!
Welcome!
So how do you test when you return JSON and you want to test that e.g. variable message of this JSON contains a String, without asserting it to a String per se?
I'm asking because I'm doing tests where the content of the String is random and cannot be guessed beforehand, we just know it should not be null.
Do you have an example or could you post one on Github where I could take a look at this?
thank you so much
Do you see any benefit in doing both unit tests and integration tests with mockito?
Isn`t @ExtendWith already included by @WebMvc?
I believe it is now, yes. You can always cmd or ctrl+click the annotation to take a look.
Does this mean that the controller cannot be unit tested?
It can be..my question to you would be if you wrote a unit test for that controller what value would it be giving you?
@@DanVega Possible shorter execution time.
Thats how I feel, I feel integration and e2e testing is more valuable than unit testing especially if you developing an IT website that pretty much just manages and displays data.
what about service layer unit testing??
The service layer could mean different things to different people. What are you trying to test in your service layer?
@@DanVega if our service layer talks repository and controller layer, wich testing should we do unit ? integration ? or both?
@@northdankota Yeah this is real life scenario. But can't find useful test case for it. Did you find?
@@hurle0409 i am not sure actually, which or why to choose these options
@ExtemdWith(SpringExtension.class) is redundant
There is no hard line between a Unit Test and an Integration Test. If you wanted a pure unit test then you would have to mock every external dependency, which would mean even mocking "String" objects. SUddenly It gets completely absurd. I have been in projects where they have written tests that are about 20 lines long, and that have tested exactly ONE line of code. The value of tests like this are next to ZERO. In my opinion unit tests are generally useless, unless you need to test complex algorithms or things like utils methods like DateUtils and that kind of thing. As soon as you start mocking too much you get tests which have no value. Integration Tests are much better because they more closely resemble Use Cases. As long as the performance/speed of these tests is good (TIP: use in memory databases!!!!! ), then you should focus on them over unit tests. Writing a test that goes from the RestController to the DB is excellent. It perfectly captures a Use Case. As long as the performance is fine..... do it like that!!!!!
When does anyone ever instantiate a controller in production code? You're righting a test for a scenario that will never occur. This "unit" test seems redundant and totally without value. You are testing your string concatenation. (Logic). A controller should not have business logic. It should delegate that to the service layer.
But the controller can contain validation
Sorry, but your background music is so annoying and distracting.
Agreed it can be. I was trying new things 🤷♂️
That is one useless video.. does not explain what to do with service and DAO dependencies..
Sorry this video didn't meet your expectations but let's discuss your comment. This video wasn't met to cover everything you need to know about writing unit and integration tests. This was simply my thoughts on the two types of test and how the lines are blurred.
If you're interested in seeing me create a tutorial on what to do with service and DAO dependencies in a certain type of test this would have been a much better comment "Thanks for the tutorial Dan... I am a little confused on what do with my service and DAO dependencies in a unit test, any chance you can break that down for me."
Great explanation. Thank you Dan