I am testing my spring boot application with unit tests and in coverage report, I have +85% branch coverage. There are some cases where some methods are covered while testing other methods such as mappers, utility methods, etc.
For example, in the service method, I called mapper and utility methods, and those methods are marked as covered in the coverage report because I tested that service method.
My question is, does it make sense to write additional tests for those mapper and utility methods since they are already covered in the service tests?
I usually take a different approach that I would like to share.
Say, I'm a developer that has got the task to create a Mapper or utility.
At this time the Service doesn't even exist.
I write my code, but then I want to check myself. So I unit test it. I don't care about the coverage at this point, for me, coverage is a tool that helps me to understand and decide whether I've made all the checks I need or I've missed an area in a code of Mapper that I wrote that possibly has a bug.
So I've made sure that my code is perfect and I submit it and move to another task...
Later (weeks, months, years) someone, me or another programmer, creates a Service that uses my code. Lets pretends its you, for example.
So you basically don't care about Mapping code, you assume that it works. However you do want to check your Service, and so you write your unit tests that can mock the dependency on Mapper or run it within the test if its not a real dependency and its fast and everything. Again you don't care about the overall coverage, you care about your code, you want to make sure that your code doesn't have bugs, and again, coverage helps you make sure that you've done your best to check your code before it meets production.
As for my old tests of Mapper - well, they're still run.
Bottom line I don't think that code should be covered for the sake of coverage, but tests (and coverage) should provide you a safety net if you wish.
With this in mind, You should write tests for your code, if you can mock other dependencies be it, if not - just run them.
P.S. I believe there might be many different opinions of this, so there is no one single right answer for this question
Do not write unittests to "cover code".
Write unittests to verify behavior.
The number of tests executing a certain line of production code does not have any meaning.
Also unittests test a unit (an arbitrary piece of code) in isolation. That means if the code under test uses other units as dependencies these other units should be replaces by test doubles (such as stubs, fakes or mocks) during the unit test.
Of course it does . Unit tests are not just for coverage . Coverage is one part of it . Your main aim is to write unit tests to avoid or minimize the bugs from testers or from production .
You should test your function with all sort of negative scenarios and positive scenarios .
apart from these you should test boundary conditions of your code .
How do we test the junit test cases we wrote? I thought manually testing ie create test data and asserting expected and actual values are okay is fine. But recently I have encountered a situation where junit tests were passing but the particular SUT code was failing during UI testing (that means the junit tests failed to guard the bug).
If your tests are passing, but the actual code that the tests were meant to cover is failing, then one of two things has happened:
The test suite hasn't adapted to cover that specific use case, or
The tests written to cover that specific use case are insufficient.
In any case, you need to rewrite your tests. Having a test suite which doesn't allow you to guard against specific aberrant behaviors makes your entire test suite worthless.
You do also mention that it fails explicitly during UI tests. This could result from a disconnect of expectations between the UI and the backend testing. In that event, either align the backend tests with the UI's actual inputs, or look to implement an integration test which covers the UI's workflow.
How do we test the junit test cases we wrote?
You should not.
Unit test are not infallible but testing tests makes no sense.
You should consider automatic tests as executable specifications.
Generally, if your specifications are wrong, you are stuck.
For automatic testing it is exactly the same thing.
To avoid this kind of problem or at least reduce it, I favor:
review of code and testing code with peers of the development team.
completing unit tests by integration and business test validated by the business team.
continuous improvement of automatic tests.
It is simple : as soon as a hole is detected in UI manual testing, an automatic test should be updated if the test exists but some checks are missing or else a new test should be created if the test is missing.
To verify quality of unit tests personally I use following techniques:
Coverage metrics. It's good idea to have good line and branch coverage. But it's usually not possible to have 100% line coverage, and coverage itself doesn't guarantee that code was actually tested rather simply called from test class.
Test code review. Personally I prefer writing tests with clear structure 'setup - run - assert'. If 'run' or 'assert' steps are missing, then there is something wrong with the test.
Mutation testing. There are frameworks which allow you to modify your production code in some simple way (apply mutators on code), then run your unit tests on modified code, and if no test fails, this code is not tested or tests are bad. For Java I use PIT Mutation Testing.
Also, sometimes it makes sense to apply not just unit tests but also some other testing techniques - manual testing, integration testing, load testing, etc.
I have encountered a situation where junit tests were passing but the
particular SUT code was failing.
Your unit tests should NOT miss the coverage of any method's functionality or their side effects. This is where the Code coverage tools like Cobertura play the role, it is NOT that the tests are passing, but we need to ensure that the each of the method's and their side effects have been unit tested/covered properly.
No, code coverage is just as bad a placebo here. You can have 100%
line coverage but still be in the same fix the OP is in?
Tools like Cobertura are there at least to find how much percentage of the code coverage we are doing, but, you will get even more bugs if you don't bother about tests coverage.
The main point is that these coverage tools don't tell you whether your internal business requirements have been really met or not.
I'm going to be implementing some unit tests using JUnit in some upcoming tasks for work. I have slight experience with JUnit from my previous employer, but while I was studying, I came across test suites. I don't have any idea if I'll be using them, but I was particularly interested in why they even exist.
Can someone give me a practical situation where I'd ever want to use a test suite, and also, what are advantages of using test suites as opposed to just using various independent tests?
EDIT: I feel this question isn't a duplicate since other answers to similar questions give a general definition, or a code snippet (as far as I could see) and I'm looking for a more practical use of suites from a design perspective. I'd like to know why bundling tests together may be a good idea, or why it may not be, etc.
Suites allow you to run multiple test classes where you can execute routines before and after the entire suite.
Testing that requires a database setup comes to mind,
load a database in memory (you can't afford to do that before and after every unit test)
Run all test cases
Unload in memory database when the entire suite is done.
#RunWith(Suite.class)
#Suite.SuiteClasses({
MyUnitTests.class
})
public class MySuiteTest {
#ClassRule
public static H2TestRule h2TestRule = new H2TestRule();
}
Here H2TestRule is a Rule for the entire suite rather than a single test case.
I am using Maven and TestNG.
How to distinguish at runtime when a particular method is being called by a TestNG/JUnit test-case or by the main java code
Several comments are alluding to this, however it's generally extremely poor practice to build in statements that work one way under test, and another way when the app is running standalone. This increases the probability that the app will pass tests, but fail in production.
Instead, you should look at why you're wanting to make this distinction. In general, it will be for the sake of some dependent object, or due to input of one variety or another. In these cases, it's better to engineer the class to accept dependent objects to be inserted into it via configuration and under test, the only thing that changes is the configuration. The class under test should not distinguish the dependant classes from one another. Instead, just work with their interfaces, so you can create mock classes for testing.
When accepting input, redirect the input source to take scripted input.
For databases, redirect to an in-memory DB which is configured for the test, etc.
You will find this approach will VASTLY improve the quality of the code you write, and decrease the probability of bugs sneaking past your unit tests.
At runtime, your code is never running unit tests. Unless you invoke them explicitly from your code, which you should never do.
Unit tests are only run manually, or during the test phase of the maven lifecycle.
Maybe my question is a newbie one, but I can not really understand the circumstances under which I would use junit?
Whether I write simple applications or larger ones I test them with the System.out statements and it seams quite easy to me.
Why create test-classes with JUnit, unnecessary folders in the project if we still have to call the same methods, check what they return and we then have an overhead of annotating everything?
Why not write a class and test it at once with System.out but not create Test-classes?
PS. I have never worked on large projects I am just learning.
So what is the purpose?
That's not testing, that's "looking manually at output" (known in the biz as LMAO). More formally it's known as "looking manually for abnormal output" (LMFAO). (See note below)
Any time you change code, you must run the app and LMFAO for all code affected by those changes. Even in small projects, this is problematic and error-prone.
Now scale up to 50k, 250k, 1m LOC or more, and LMFAO any time you make a code change. Not only is it unpleasant, it's impossible: you've scaled up the combinations of inputs, outputs, flags, conditions, and it's difficult to exercise all possible branches.
Worse, LMFAO might mean visiting pages upon pages of web app, running reports, poring over millions of log lines across dozens of files and machines, reading generated and delivered emails, checking text messages, checking the path of a robot, filling a bottle of soda, aggregating data from a hundred web services, checking the audit trail of a financial transaction... you get the idea. "Output" doesn't mean a few lines of text, "output" means aggregate system behavior.
Lastly, unit and behavior tests define system behavior. Tests can be run by a continuous integration server and checked for correctness. Sure, so can System.outs, but the CI server isn't going to know if one of them is wrong–and if it does, they're unit tests, and you might as well use a framework.
No matter how good we think we are, humans aren't good unit test frameworks or CI servers.
Note: LMAO is testing, but in a very limited sense. It isn't repeatable in any meaningful way across an entire project or as part of a process. It's akin to developing incrementally in a REPL, but never formalizing those incremental tests.
We write tests to verify the correctness of a program's behaviour.
Verifying the correctness of a program's behaviour by inspecting the content of output statements using your eyes is a manual, or more specifically, a visual process.
You could argue that
visual inspection works, I check that the code does what it's meant to
do, for these scenarios and once I can see it's correct we're good to
go.
Now first up, it's great to that you are interested in whether or not the code works correctly. That's a good thing. You're ahead of the curve! Sadly, there are problems with this as an approach.
The first problem with visual inspection is that you're a bad welding accident away from never being able to check your code's correctness again.
The second problem is that the pair of eyes used is tightly coupled with the brain of the owner of the eyes. If the author of the code also owns the eyes used in the visual inspection process, the process of verifying correctness has a dependency on the knowledge about the program internalised in the visual inspector's brain.
It is difficult for a new pair of eyes to come in and verify the correctness of the code simply because they are not partnered up with brain of the original coder. The owner of the second pair of eyes will have to converse with original author of the code in order to fully understand the code in question. Conversation as a means of sharing knowledge is notoriously unreliable. A point which is moot if the Original Coder is unavailable to the new pair eyes. In that instance the new pair of eyes has to read the original code.
Reading other people's code that is not covered by unit tests is more difficult than reading code that has associated unit tests. At best reading other peoples code is tricky work, at its worst this is the most turgid task in software engineering. There's a reason that employers, when advertising job vacancies, stress that a project is a greenfield (or brand new) one. Writing code from scratch is easier than modifying existing code and thereby makes the advertised job appear more attractive to potential employees.
With unit testing we divide code up into its component parts. For each component we then set out our stall stating how the program should behave. Each unit test tells a story of how that part of the program should act in a specific scenario. Each unit test is like a clause in a contract that describes what should happen from the client code's point of view.
This then means that a new pair of eyes has two strands of live and accurate documentation on the code in question.
First they have the code itself, the implementation, how the code was done; second they have all of the knowledge that the original coder described in a set of formal statements that tell the story of how this code is supposed to behave.
Unit tests capture and formally describe the knowledge that the original author possessed when they implemented the class. They provide a description of how that class behaves when used by a client.
You are correct to question the usefulness of doing this because it is possible to write unit tests that are useless, do not cover all of the code in question, become stale or out of date and so on. How do we ensure that unit tests not only mimics but improves upon the process of a knowledgeable, conscientious author visually inspecting their code's output statements at runtime? Write the unit test first then write the code to make that test pass. When you are finished, let the computers run the tests, they're fast they are great at doing repetitive tasks they are ideally suited to the job.
Ensure test quality by reviewing them each time you touch off the code they test and run the tests for each build. If a test fails, fix it immediately.
We automate the process of running tests so that they are run each time we do a build of the project. We also automate the generation of code coverage reports that details what percentage of code that is covered and exercised by tests. We strive for high percentages. Some companies will prevent code changes from being checked in to source code control if they do not have sufficient unit tests written to describe any changes in behaviour to the code. Typically a second pair of eyes will review code changes in conjunction with the author of the changes. The reviewer will go through the changes ensure that the changes understandable and sufficiently covered by tests. So the review process is manual, but when the tests (unit and integration tests and possibly user acceptance tests) pass this manual review process the become part of the automatic build process. These are run each time a change is checked in. A continuous-integration server carries out this task as part of the build process.
Tests that are automatically run, maintain the integrity of the code's behaviour and help to prevent future changes to the code base from breaking the code.
Finally, providing tests allows you to aggressively re-factor code because you can make big code improvements safe in the knowledge that your changes do not break existing tests.
There is a caveat to Test Driven Development and that is that you have to write code with an eye to making it testable. This involves coding to interfaces and using techniques such as Dependency Injection to instantiate collaborating objects. Check out the work of Kent Beck who describes TDD very well. Look up coding to interfaces and study design-patterns
When you test using something like System.out, you're only testing a small subset of possible use-cases. This is not very thorough when you're dealing with systems that could accept a near infinite amount of different inputs.
Unit tests are designed to allow you to quickly run tests on your application using a very large and diverse set of different data inputs. Additionally, the best unit tests also account for boundary cases, such as the data inputs that lie right on the edge of what is considered valid.
For a human being to test all of these different inputs could take weeks whereas it could take minutes for a machine.
Think of it like this: You're also not "testing" something that will be static. Your application is most likely going through constant changes. Therefore, these unit tests are designed to run at different points in the compile or deployment cycle. Perhaps the biggest advantage is this:
If you break something in your code, you'll know about it right now, not after you deployed, not when a QA tester catches a bug, not when your clients have cancelled. You'll also have a better chance of fixing the glitch immediately, since it's clear that the thing that broke the part of the code in question most likely happened since your last compile. Thus, the amount of investigative work required to fix the problem is greatly reduced.
I added some other System.out can NOT do:
Make each test cases independent (It's important)
JUnit can do it: each time new test case instance will be created and #Before is called.
Separate testing code from source
JUnit can do it.
Integration with CI
JUnit can do it with Ant and Maven.
Arrange and combine test cases easily
JUnit can do #Ignore and test suite.
Easy to check result
JUnit offers many Assert methods (assertEquals, assertSame...)
Mock and stub make you focus on the test module.
JUnit can do: Using mock and stub make you setup correct fixture, and focus on the test module logic.
Unit tests ensure that code works as intended. They are also very helpful to ensure that the code still works as intended in case you have to change it later to build new functionalities to fix a bug. Having a high test coverage of your code allows you to continue developing features without having to perform lots of manual tests.
Your manual approach by System.out is good but not the best one.This is one time testing that you perform. In real world, requirements keep on changing and most of the time you make a lot of modificaiotns to existing functions and classes. So… not every time you test the already written piece of code.
there are also some more advanced features are in JUnit like like
Assert statements
JUnit provides methods to test for certain conditions, these methods typically start with asserts and allow you to specify the error message, the expected and the actual result
Some of these methods are
fail([message]) - Lets the test fail. Might be used to check that a certain part of the code is not reached. Or to have failing test before the test code is implemented.
assertTrue(true) / assertTrue(false) - Will always be true / false. Can be used to predefine a test result, if the test is not yet implemented.
assertTrue([message,] condition) - Checks that the boolean condition is true.
assertEquals([message,] expected, actual) - Tests whether two values are equal (according to the equals method if implemented, otherwise using == reference comparison). Note: For arrays, it is the reference that is checked, and not the contents, use assertArrayEquals([message,] expected, actual) for that.
assertEquals([message,] expected, actual, delta) - Tests whether two float or double values are in a certain distance from each other, controlled by the delta value.
assertNull([message,] object) - Checks that the object is null
and so on. See the full Javadoc for all examples here.
Suites
With Test suites, you can in a sense combine multiple test classes into a single unit so you can execute them all at once. A simple example, combining the test classes MyClassTest and MySecondClassTest into one Suite called AllTests:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({ MyClassTest.class, MySecondClassTest.class })
public class AllTests { }
The main advantage of JUnit is that it is automated rather than you manually having to check with your print outs. Each test you write stays with your system. This means that if you make a change that has an unexpected side effect your test will catch it and fail rather than you having to remember to manually test everything after each change.
JUnit is a unit testing framework for the Java Programming Language. It is important in the test driven development, and is one of a family of unit testing frameworks collectively known as xUnit.
JUnit promotes the idea of "first testing then coding", which emphasis on setting up the test data for a piece of code which can be tested first and then can be implemented . This approach is like "test a little, code a little, test a little, code a little..." which increases programmer productivity and stability of program code that reduces programmer stress and the time spent on debugging.
Features
JUnit is an open source framework which is used for writing & running tests.
Provides Annotation to identify the test methods.
Provides Assertions for testing expected results.
Provides Test runners for running tests.
JUnit tests allow you to write code faster which increasing quality
JUnit is elegantly simple. It is less complex & takes less time.
JUnit tests can be run automatically and they check their own results and provide immediate feedback. There's no need to manually comb through a report of test results.
JUnit tests can be organized into test suites containing test cases and even other test suites.
Junit shows test progress in a bar that is green if test is going fine and it turns red when a test fails.
I have slightly different perspective of why JUnit is needed.
You can actually write all test cases yourself but it's cumbersome. Here are the problems:
Instead of System.out we can add if(value1.equals(value2)) and return 0 or -1 or error message. In this case, we need a "main" test class which runs all these methods and checks results and maintains which test cases failed and which are passed.
If you want to add some more tests you need to add them to this "main" test class as well. Changes to existing code. If you want to auto detect test cases from test classes, then you need to use reflection.
All your tests and your main class to run tests are not detected by eclipse and you need to write custom debug/run configurations to run these tests. You still don't see those pretty green/red colored outputs though.
Here is what JUnit is doing:
It has assertXXX() methods which are useful for printing helpful error messages from the conditions and communicating results to "main" class.
"main" class is called runner which is provided by JUnit, so we don't have to write any. And it detects the test methods automatically by reflection. If you add new tests with #Test annotation then they are automatically detected.
JUnit has eclipse integration and maven/gradle integration as well, so it is easy to run tests and you will not have to write custom run configurations.
I'm not an expert in JUnit, so that's what I understood as of now, will add more in future.
You cannot write any test case without using testing framework or else you will have to write your testing framewok to give justice to your test cases.
Here are some info about JUnit Framework apart from that you can use TestNG framework .
What is Junit?
Junit is widely used testing framework along with Java Programming Language. You can use this automation framework for both unit testing and UI testing.It helps us define the flow of execution of our code with different Annotations. Junit is built on idea of "first testing and then coding" which helps us to increase productivity of test cases and stability of the code.
Important Features of Junit Testing -
It is open source testing framework allowing users to write and run test cases effectively.
Provides various types of annotations to identify test methods.
Provides different Types of Assertions to verify the results of test case execution.
It also gives test runners for running tests effectively.
It is very simple and hence saves time.
It provides ways to organize your test cases in form of test suits.
It gives test case results in simple and elegant way.
You can integrate jUnit with Eclipse, Android Studio, Maven & Ant, Gradle and Jenkins
JUNIT is the method that is usually accepted by java developer.
Where they can provide similar expected input to the function and decide accordingly that written code is perfectly written or if test case fails then different approach may also need to implement.
JUNIT will make development fast and will ensure the 0 defects in the function.
JUNIT : OBSERVE AND ADJUST
Here is my perspective of JUNIT.
JUNIT can be used to,
1)Observe a system behaviour when a new unit is added in that system.
2)Make adjustment in the system to welcome the "new" unit in the system.
What? Exactly.
Real life eg.
When your relative visits your college hostel room,
1) You will pretend to be more responsible.
2) You will keep all things where they should be, like shoes in shoe rack not on chair, clothes in cupboard not on chair.
3) You will get rid of all the contraband.
4) you will start cleanUp in every device you posses.
In programming terms
System: Your code
UNIT: new functionality.
As JUNIT framework is used for JAVA language so JUNIT = JAVA UNIT (May be).
Suppose a you already have a well bulletproof code, but a new requirement came and you have to add the new requirement in your code. This new requirement may break your code for some input(testcase).
Easy way to adapt this change is using unit testing (JUNIT).
For that you should write multiple testcases for your code when you are building your codebase. And whenever a new requirement comes you just run all the test cases to see if any test case fails.
If No then you are a BadA** artist and you are ready to deploy the new code.
If any of the testcases fail then you change your code and again run testcases until you get the green status.