Assume vs assert in JUnit tests - java

I have read that assume will not run the test if assumption failed,
but I am not sure regarding the logic of when to place assert vs assume.
For example: any resource loading check should be done with assume?
When should I use assume over assert?
(Note: i am looking for correct design of when to use one over the other)

You would use assume if you have circumstances under which some tests should not run at all. "Not run" means that it cannot fail, because, well, it did not run.
You would use assert to fail a test if something goes wrong.
So, in a hypothetical scenario where:
you have different builds for different customers, and
you have some resource which is only applicable to a particular client, and
there is something testable about that resource, then
you would write a test which:
assumes that the resource is present, (so the test will not run on customers that do not have that resource,) and then
asserts that everything about the resource is okay (so on the customer that does actually have the resource, the test makes sure that the resource is as it should be.)

The Assert class is the workhorse of JUnit and is the class JUnit testers are most familiar with. Most JUnit assert signatures are similar in nature. They consist of an optional message, an expected instance or variable and the actual instance or variable to be compared. Or, in the case of a boolean test like True, False, or Null, there is simply the actual instance to be tested.
The signature with a message simply has an initial parameter with a message string that will be displayed in the event the assert fails:
assert<something>(“Failure Message String”, <condition to be tested>);
Assumptions:
You’ve probably heard that it’s best not to work on assumptions so here is a testing tool JUnit gives you to ensure your tests don’t.
Both Asserts and Assumes stop when a test fails and move on to the next test. The difference is that a failed Assert registers the failure as a failed test while an Assume just moves to the next test. This permits a tester to ensure that conditions, some of which may be external and out of control of the tester, are present as required before a test is run.
There are four varieties of Assumes: one to check a boolean condition, one to check that an exception has not occurred, one to check for null objects, and one that can take a Hamcrest matcher. As seen in the Assert section above, the ability to take a Hamcrest matcher is a gateway to testing flexibility.
You can read more here
https://objectcomputing.com/resources/publications/sett/march-2014-junit-not-just-another-pretty-assert/
In short Assume used to disable tests, for example the following disables a test on Linux: Assume.assumeFalse(System.getProperty("os.name").contains("Linux"));
Assert is used to test the functionality.

The most easiest difference between Assert and Assume is :
Assume will only run when the assumption is true. Will be skipped if it false.
assumeTrue(boolean assumption, String message)
Assert will run normally if true.
In case of false assert, it gives predefined error message.
assertTrue(boolean condition, String message)

Simply check out the javadoc for Assume:
A set of methods useful for stating assumptions about the conditions in which a test is meaningful. A failed assumption does not mean the code is broken, but that the test provides no useful information.
In other words: when an assert fires, you know that your testcase failed. Your production code isn't doing what you expect it to do.
Assume means ... you don't know exactly what happened.

Related

I don't want assertJ assertThat ends test when assertion fails

I use assertJ and have multiple assertThat assertions in my test case.
When first assertion fails test is finished but I don't want that.
I'd like to have information about all failing assertions after single executing of test case.
Is it any way to do that ?
I have found solution with SoftAssertions here -> http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#soft-assertions
but it's ugly to add variable. before each assertThat
A bit of example code would help, but then, this is more of a theoretical problem, as the real answer is: consider not having multiple assertions in one test call!
Meaning: the idea of a failing test is to get you to a problem as quickly as possible. When you combine multiple asserts into a single test, then you make our life harder by default. Because instead of knowing "test X with assertion Y failed, you have to first study logs very carefully to identify which asserts passed, and which one failed.
Therefore the recommend practice is to not put multiple asserts/check into a single test.
If you don't like soft assertions, you can give a try to JUnit 5 assertAll but otherwise I would follow #GhostCat advice and try to assert one thing per test (that usually leads to only a few assertions).
I think that in some cases you may and sometimes even you have to assert multiple things in a single test method if your method perform multiple changes that you should check through different levels/abstractions.
For example as you test a method that adds an element in a object that stores it, you can assert that the number of elements contained in the object were incremented by one but you can also check that the new element were correctly added concerning its values.
You have two levels/abstractions : the object that contains the element that has a "direct/core" state and the elements that it contains that have their own states.
In splitting it in two assertions, it would give a test that looks like :
#Test
public void addElt(){
foo.addElt(new Element("a name", "a role"));
assertThat(foo).extracting(Foo::getSize)
.contains(actualSize+1);
assertThat(foo.getLastElt()).extracting(Element::getName, Element::getRole)
.containsExactly(addedElt.getName(), addedElt.getRole());
}
So now why trying to couple two assertions that checks two different
things ?
Does it really bring a value for debugging your test ?
I don't think so.
Trying to assert the changes on the two level of abstraction in a single assertion makes clearly no sense : complex and useless noises.
If the first assertion fails :
assertThat(foo).extracting(Foo::getSize)
.contains(actualSize+1);
It very probably means that the element was not added.
So in this case, performing the second assertion :
assertThat(foo.getLastElt()).extracting(Element::getName, Element::getRole)
.containsExactly(addedElt.getName(), addedElt.getRole());
makes no sense as it will very probably be also in error.
The developer that handles the failure test needs only to have useful information and not noise that can make its solving harder. So having a feedback about the size that is not which one expected is just what you need.
What I try to explain is right for AssertJ as for any testing framework.

Is there a way to track each assertion of a multiple assertion test case in JUnit? [duplicate]

This question already has answers here:
Continuing test execution in junit4 even when one of the asserts fails
(7 answers)
Closed 6 years ago.
I am somewhat new to TDD and JUnit, I know that I can write test cases for methods I am implementing in my code.
And obviously, there are methods in my code which need several corner cases to be tested in order to verify that method implementation is OK. Since generally the good practice is keeping one test method per one method in code, I have to add multiple assertions for that kind of a method as explained in this answer. https://stackoverflow.com/a/762582/5715934
public void testValueOf() {
assertEquals(1, Integer.valueOf("1").intValue());
assertEquals(0, Integer.valueOf("0").intValue());
assertEquals(-1, Integer.valueOf("-1").intValue());
assertEquals(Integer.MAX_VALUE, Integer.valueOf("2147483647").intValue());
assertEquals(Integer.MIN_VALUE, Integer.valueOf("-2147483648").intValue());
....
}
But when I am executing the test case, I am not getting test status (pass/fail) for each assertion inside the test method. Instead, it shows 'red' even if one assertion is failed and green if all are passed.
Isn't it easier to have the track of each assertion to make debugging easier? And is there any formal way/tool/workaround to do that (JUnit 4)?
First of all it is NOT a good idea to have a single test method for single method, quite the opposite. In your code above each of the asserts should actually be a separate test method.
This doesn't mean that you will always have a single assert in test method, this will be the case only for the simplest ones. If a method e.g. returns an object you will have more asserts that validate that this object is good.
But the most important thing is that the method under tests is called usually only once.
The only way to know which assertion failed is by looking at the message/stack trace. But generally if a test fails you know that something is wrong, you open IDE and look at the test.

Why doesn't Guava have postconditions? What can I use instead?

So, Guava has simple yet useful Preconditions to check method arguments. But I guess it would be reasonable to have a "Postconditions" class too. Or is it just because java provides assertions?
Since a class like this doesn't exist, what is the "best" (practice) alternative way to check postonditions before a mathod returns?
Testing post conditions would be superfluous .
The way we test post-conditions in java is by unit testing.
With unit testing, we make sure that for a given input we get predictable output. With Preconditions, we can verify that we have valid input, and hence the output is already guaranteed by the tests.
I would use the Java assert keyword within the method itself to encode the postcondition.
Unit Test or Postcondition?
Unit tests and postconditions serve different purposes.
An assertion in a unit test provides a check on the result of a method for one input vector. It is an oracle specifying the expected outcome for one specific case.
An assert in the method itself verifies that for any input the postcondition holds. It is an oracle specifying (properties of) the expected outcome for all possible cases.
Such a postcondition-as-oracle combines well with automated testing techniques in which it is easy to generate inputs, but hard to generate the expected value for each input.
Guava Postconditions?
As to why Guava has a Precondition class, but no Postcondition class, here's my understanding.
Guava Preconditions effectively provides a number of shorthands for common situations in which you'd want to throw a particular kind of exception (Illegal argument, null pointer, index out of bounds, illegal state) based on the method's inputs or the object's state.
For postconditions there are fewer such common cases. Hence there is less need to provide a shorthand throwing specific kinds of exceptions. A failing postcondition is like a HTTP 500 "Internal Server Error" -- all we know something went wrong executing our method.
(Note that Guava's notion of precondition is quite different from that of pure design-by-contract, in which there are no guarantees at all if a precondition is not met -- not even that a reasonable exception is thrown. Guava's Preconditions class provides useful capabilities to make a public API more defensive).
Preconditions and postconditions serve very different purposes.
Preconditions test the input, which is not under the method's control; postconditions test the output, which is. Therefore they make no sense inside the method itself, but only as outside code that tests the method.
However, if you really wanted to put such assertions in your code, the Guava Preconditions would serve pretty well for that, too, even if that is not their intended purpose.

Testing for optional exception in parameterized JUnit 4+ test

I am trying to write a unit test for a method which takes a string as a para-
meter and throws an exception if it is malformed (AND NONE if it is okay).
I want to write a parameterized test which feeds in several strings and the
expected exception (INCLUDING the case that none is thrown if the input
string is well-formed!). If trying to use the #Test(expect=SomeException.class)
annotation, I encountered two problems:
expect=null is not allowed.
So how could I test for the expected outcome of NO exception to be thrown
(for well-formed input strings)?
expect= not possible?
I not yet tried it, but I strongly suspect that this is the case after
reading this (could you please state whether this is true?):
http://tech.groups.yahoo.com/group/junit/message/19383
This then seems to be the best solution I found yet. What do you think about
it, especially compared to that:
How do I test exceptions in a parameterized test?
Thank you in advance for any help, I look forward the discussion :)
Create two test case classes:
ValidStringsTest
InvalidStringsTest
Obviously the first one tests all sorts of valid inputs (not throwing an exception), whilst the second one always expects the exception.
Remember: readability of your tests is even more important than readability of production code. Don't use wacky flags, conditions and logic inside JUnit test cases. Simplicity is the king.
Also see my answer here for a hint how to test for exceptions cleanly.
Have two different tests - one for valid inputs and one for invalid ones. I haven't used JUnit 4 so I can't comment on the exact annotation format - but basically you'd have one parameterized test with various different invalid inputs, which says that it does expect an exception, and a separate test with various different valid inputs which doesn't say anything about exceptions. If an exception is thrown when your test doesn't say that it should be, the test will fail.
Splitting the test cases into two test classes is the appropriate approach in many cases - as both Tomasz and Jon already outlined.
But there are other cases where this split is not a good choice just in terms of readability. Let's assume the rows in the tested data set have a natural order and if the rows are sorted by this natural order it may be easy to see whether or not the test data covers all relevant use cases. If one splits the test cases into two test classes, there is no longer an easy way to see whether all relevant test cases are covered. For these cases
How do I test exceptions in a parameterized test?
seeems to provide the best solution indeed.

spirit of a jUnit test

Suppose that you have the following logic in place:
processMissing(masterKey, masterValue, p.getPropertiesData().get(i).getDuplicates());
public StringBuffer processMissing(String keyA, String valueA, Set<String> dupes) {
// do some magic
}
I would like to write a jUnit test for processMissing, testing its behavior in event dupes is null.
Am i doing the right thing here? Should I check how method handles under null, or perhaps test method call to make sure null is never sent?
Generally speaking, what is the approach here? We can't test everything for everything. We also can't handle every possible case.
How should one think when deciding what tests to write?
I was thinking about it as this:
I have a certain expectation with the method
Test should confirm define my expectation and confirm method works under that condition
Is this the right way to think about it?
Thanks and please let me know
First, define whether null is a valid value for the parameter or not.
If it is, then yes, definitely test the behavior of the method with null.
If it is not, then:
Specify that constraint via parameter documentation.
Annotate that constraint on the parameter itself (using an annotation compatible with the tool below).
Use a static analysis tool to verify that null is never passed.
No unit test is required for the invalid value unless you're writing code to check for it.
The static analysis tool FindBugs supports annotations such as #NonNull, with some limited data-flow analysis.
I personally think it would be unnecessarily expensive within large Java codebases to always write and maintain explicit checks for NULL and corresponding, non-local unit tests.
If you want to ensure that people don't call your API with a null argument you may want to consider using annotations to make this explicit, JSR 305 covers this, and its used in Guava. Otherwise you're relying on users reading javadoc.
As for testing, you're spot on in that you can't handle every possible case, assuming you don't want to support null values, I'd say that you may want to throw an IllegalArguemntException rather than a NullPointerException so you can be explicit about what is null, then you can just test for that exception being thrown - see JUnit docs.

Categories

Resources