I am trying to write some unit tests for testing my service layer which I am doing well I think, the service layer as a dependency on a repository so am mocking a repository using RhinoMocks, so I am testing the Service layer "WITHOUT" hitting the database which is great.
Now I need to test my repository layer, this has a direct connection to a database so I have to test it don't i? I have no other option but to test it?
If I test another implementation of the Repository that doesn't hit the database then this is no testing my implementation.
I have managed to mock out all lower layers so anything that depended on code that takes a while to run ie. The repository, then I mocked this out. The result is that all my tests for layers below the repository complete fast and do not hit the database.
The problem is what do I now do with the repository. I have to test it but it has a dependency on a SQL database.
Well, the general answer goes like this. I would write unit tests that verifies the logic of the repository layer and break out the sql dependency in a new class and mock it in the tests of the repo. If the repository layer contains only a sql connection and no logic there is nothing to unit test in my opinion. Then you are more suitable with integration tests with the database connected.
Thus mocking code you don't own is a bad practice, I think best option for you is to test repositories via acceptance/integration tests
You certainly can test your repository layer without talking to a database. Most ADO.net classes are mockable, if you are careful about how you create them and you are careful to couple to interfaces instead of concretions. Unfortunately, ADO.net was created before mocking was a very popular practice, and it is still a bit of a pain to do.
The real question in my mind is whether you should try to mock them. The benefits of mocking are twofold: they run faster, and they force you to encapsulate more details about your database (making it easier to switch out db technologies, if you ever want to do it). The benefits of functional tests are that they also test your database layer (stored procedures, etc), they are arguably easier to write, and they are easier to maintain in the sense that if a db change is made, integration tests notice automatically, instead of you hunting the mocked out tests down.
I would say the "best" approach would be to test them both with moqs and with the real database, since this gives you the best of both worlds. However, it is quite costly of course.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Hello stackoverflow community.
I had an argument at work regarding if repository tests for spring-data JPA (or the Micronaut version) are necessary at all.
This would be my setup of the application:
#Controller ➡ #Service/#Sigleton ➡ Repository<Entity>
in my service tests I'd use the #ExtendWith(SpringExtension::class) extension (Junit5)
when creating the test setup, I'd #MockBean away other systems I need to call (like REST-APIs) but #Autowire my Repository's.
When setting up my test data I'd simply save my required entities into an H2 in-memory database by using the injected repositories.
This will test my database logic and business logic as well. In case of 100% test coverage I've tested all the database calls which can happen in production.
However what I usually see in projects is that the Repository is mocked away.
To test the custom repository calls there are separate Tests to make sure the repository functions work as expected.
What are your comments on this. Do you prefer the approach without repository mocks or with and why?
I have no experience with Micronaut, but I believe my answer will apply to both of the frameworks:
There are different types of integration tests supported by spring for example.
Basically the fact that you're running a spring context in the test, already means that its more than a unit test. In general the Spring test package is for integration tests.
Now in Spring there are annotations like #DataJpaTest, #WebMvcTest. They create a "slice" of application context loading only necessary beans, and mocking / omitting others. For example, in #WebMvcTest the JPA repositories are anot loaded at all.
You can also create your own slices.
Now If you want to check your rest layer (Controller is defined correctly, request is validated in a proper way, upon the request you're getting a response in a proper format and so forth) you can use #WebMvcTest.
If you want to test that the sql queries are correct - that you can use #DataJpaTest (assuming you work with JPA / Spring Data of course).
Now, If you want to test service logic, sometimes you don't even need an integration test (loading spring context) since you can run a unit test for services and mock out the repository calls or calls to external services if you have those.
Regarding the H2 approach. While people use it for testing their DB layer (SQL queries), sometimes it doesn't work exactly like your database in production. This means that sometimes you can't really run the same SQL query in tests. For these cases I recommend TestContainers project: run the Docker image of your db on startup of the test and stop the image after the test ends.
Update
Based on OP's comment:
lot of the 'mysql query' is already been taken care of by the framework, so why should I explicitly test the repository
This is subjective, but let me put it this way: Tests are a tool to gain a confidence a code for developer first of all.
If the developer wants to be sure that the query behaves as expected then the test is a tool that can help. Specifically regarding Queries: Maybe the query is just wrong, maybe its a native query that should be checked anyway. Maybe there are many queries that run one after another. Its only up to you to decide.
Is it worth it to write Unit tests for services?
Well, this depends on what do the services actually do.
If they run a complicated algorithm that can't be easily checked by integration tests (like service requires various mocks in various cases) then unit tests for services can be done.
Besides, in general, unit tests are way faster than Spring's tests. So (again subjective) my personal rule is: if you can gain the confidence in code with unit test - do it. If you need to check integration - go for integration test.
If you are not mocking your Repository in service junits, then it is an Integration test and not a Unit test. And it is fine if you want to keep it this way.
But if you want to write unit tests, which tests your individual layers then you should mock your Repository and write separate integration tests for Repository.
I'm following TDD technique in my new Laravel project. Thus I have a set of tests which cover my controllers, model classes, services, etc. Most of these tests are HTTP tests, so I stored them in the /tests/Feature directory. Additionally I have few unit tests, which cover quite specific methods, which are not (easily) reachable from the HTTP tests.
If I understand correctly, each HTTP test is a functional tests, because it covers a lot of classes included Controller. Should I in that situation separately create unit tests for each method in my project even if it is already covered by HTTP tests? If yes, what benefit can I take from it.
Thank you in advance for explanations.
The philosophy of creating unit tests is to test a small piece of your code, for example, if you have an API, so it only returns the list of 10 recent posts then I guess it's no need to create a unit test for that and it can be covered with writing the functional or HTTP tests. But let's assume you have an endpoint that the user uses that endpoint to upgrade his account from regular type to golden type so he/she can access more posts or videos. There will be definitely a lot of things going on in that endpoint, so yeah you need to write Unit tests in addition to functional tests. Also, one more thing is that when you write functional tests you should see it from the QA perspective, I can categorize it like this
Functional/Http/Feature => [Validation Checks, Response Checks=>[The endpoint throw an error in different situations or return success if all goes well]]
Unit => [Write the test for the small functions that they get called by that endpoint Or write the test for that endpoint and mock everything so you can get what you expect]
Integration => [Write tests for the third party APIs or database persistence or caching persistence that you are using in your application]
So if you have an endpoint and you are writing tests for that endpoint and your functional tests has covered some part of that endpoint logic then I guess it's not necessary to write more unit tests for it.
Let say your website need to call Twitter API to perform some tasks, you have several options:
Only use mock
Use mock in unit test, but use production api in integration test
Only call production api, never use mock
Which one is the best approach if your services depends on the external api?
I would step back and ask yourself what you are trying to test.
If you are trying to test your other code in isolation, use a mock (that's the purpose of a mock after all).
If you are trying to really test end-to-end, use the production API (or a live test API if they have one).
So my answer is pretty close to your #2 choice, with the caveat that you should consider whether you need to test an API from a third party. Sometimes it makes sense to do so or is necessary, sometimes it doesn't make sense (they are known to be reliable or it's very inconvenient to do so).
I think the second one is the best solution. I use mocks in unit test and production api in functional tests.
I don't want the unit test use the remote api because i want them to run fast and i'm not testing the result (and connection) of that api, but I want my Jenkins fails if the api has changed or i have a connection problem or whatever
One advantage of using Mock is for 'negative testing', e.g. how your code responds to certain error conditions returned from the API. Using Mock it is possible to test 100% of your 'reachable' code, whereas this would be problematic using a real API (in particular one provided externally to your organization).
What are the best Junit tests for soap services.
Would connecting to the web service fall under a unit test or an integration test?
I need to pick useful unit tests and was looking for ideas on tests that would be automatable and repeatable.
Thanks.
For unit tests, you should test an isolated behavior of a single class, and therefore use mocks/stubs/test doubles as much as possible. If you do not mock, then you are not testing an isolated part of your code. Hence isolating the error becomes more difficult and the test might also not be repeatable (e.g. strange network behavior might occur unrepeatably).
You should also try to automate your integration tests, where you replace your mocked objects with the real implementations.
At this infoq site you can find a short introduction about mocking web services, and several links to tutorials/tools/whitepapers.
I am building a web application that uses the database for Users, Security/roles, and to store content.
It seems a little daunting to me to begin on the road of unit testing because I have to make sure my database has been initialized properly for my tests to run.
What are common practices to help in this regard?
i.e. while developing/testing, I might delete a user, but for my test to pass that user has to be in the database, along with his profile, security settings etc.
I know I can create a setup script, something to recreat the databas etc.
I don't want to end up spending my entire time maintaining my tests and ensuring my database is in sych
Or is that the cost of Unit Testing/TDD?
The solution is Mocking. Mocks "replace" the connection. The unit under test will "connect" to the Mock and executes its statement. The Mock returns normal resultsets o.s.e.
After the test, the mock can give you a list of all methods, that were called by the unit under test. Easymock.org
As the other said: DB connection aren't a unit test. So drop it and do it local with Mocking objects
It's not a unit test if you are testing more than one unit.
Usually you'll have one component (your page, or the business layer) talking to a data layer object that is responsible for actually connecting and querying the database. My recommendation is to develop a unit test for the first component, using dependency injection to pass in a mock version of the DataLayer (which acts on hardcoded data, or a List you pass in, etc). This way you are testing your higher level code in isolation from the other components.
Then you are free to develop other unit tests (and integration tests) for the data layer to ensure that it is handling it's job (writing to the database) correctly.
We use an in-memory database (hsqldb) for our unit tests. In the setup we populate it with test data and then before each test case we start a transaction and after each test case we roll it the transaction back. This means each testcase has a clean start of the db.
It sounds like you actually want functional/integration testing. For Web applications I recommend you look into Selenium or Canoo WebTest.
These are also great for automating tasks you do on the Web. I have a set-up suite and a tear-down suite that create business entities and testing users through the admin interface as well as tests for the customer-facing site.
Michael Feathers argues that tests that communicate with databases aren't unit tests by definition. The main reason for this is the point you bring up: unit tests should be simple and easy to run.
This isn't to say that you shouldn't test database code. But you don't want to consider them unit tests. Thus, if you do any database testing, you want to separate the tests from the rest of your unit tests.
Since I used Doctrine for my PHP database work, and since Doctrine has a query abstraction layer (called DQL), I can swap out back ends without having to worry too much about compatibility issues. So in this case for my unit tests I would just at the beginning of my tests load the schema and fixtures into a SQLlite db, test my models, and discard the SQLlite db at the end of testing.
This way I've tested my models and data access to make sure their queries are formed correctly.
Now testing the specific database instance to make sure the current schema is correct is a different story and IMHO probably doesn't belong in your Unit Tests, so much as it belongs in your deployment task list.
The cost of unit testing/TDD is that you have to alter your design so that you have a clean separation between the database and the domain layer, so that you can create a fake that will allow you to create tests that don't hit the database.
But that cleaner design is just the beginning of the cost. After that you have to create tests that both help you make the code work right the first time and alert you when anyone breaks something that used to work.
And after you have a good fundamental design with tests that protect your existing functionality, you'll find yourself cleaning up code to make it easier to work with, with confidence you aren't breaking things along the way.
And so on and so on... The costs of unit testing/TDD just keep piling up over time.
For Java, you may also want to look into dbunit. http://www.dbunit.org/