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.
Related
It is good practise to match mock objects widely but verify them precisely.
for example:
Using this:
when(myMock.has(any())).thenReturn(myValue);
Rather than:
when(myMock.has(eq("blah")).thenReturn(myValue);
Along with:
var result = myMethod();
assertThat(result, is(myValue));
Because it is making sure that it is always returned myValue regardless of the has method input.
There was a good explanation for this rule but I can not find it.
something along the lines: match widely and verify precisely.
It would be great if you can advise me about the name of the rule or some reference to it?
The explanation is quite simple: It will make your live easier.
Imagine the case that a caller will not call your method with "blah". In this case you rely on the mocking framework what will be returned, most likely null, zero or false. Your test will then run into a different direction or even fail with a NullpointerException. For other developers it will be hard to understand what went wrong here.
If you match widely, your test will continue as expected, but you should place a verification afterwards that makes the test fail with a clean reason. Developers tend to omit the verification step, wich renders the test useless quite often.
Usually there is no reason to match on a precise parameter value, except for the case when you want your mock to act differently on two values.
Most frameworks provide methods for the method call verification, e.g. Mockito:
#Mock
private Repository repository;
#Test
private void testReadData() {
Mockito.when(repository.findById(any())).thenReturn(yourEntity);
// run your test
Mockito.verify(repository).findById("foo");
}
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.
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.
Some java method is null safe, but some are not. How to distinguish them?
I assume you mean in terms of the parameters? The documentation should state whether or not the arguments can be null, and when they can be null, what semantic meaning is inferred from nullity.
Unfortunately not all documentation is clear like this - and likewise it may not specify whether the return value might be null or not... in which case all you can do is experiment or look at the source code where possible :(
In general, I would suggest that you assume that you cannot pass null as a parameter unless the documentation clearly states that you can and what the corresponding behaviour is.
A problem with taking the default assumption that a parameter might be "null-safe" is that, even if that turns out to be true, it's not always clear without documentation what the corresponding behaviour actually is. "Not throwing an exception" doesn't actually indicate what alternative behaviour/default parameter/assumptions are then going to occur instead.
If you're designing an API, then where is's practical, I would suggest not actually encouraging null to be passed as a parameter to exposed methods/constructors, but rather have separate method signatures that include or not the various optional parameters. And in any case, you may then need to document in some way what actual behaviour is being taken to make up for the missing parameter.
If you're lucky, the parameter will be documented or annotated, or both. Unfortunately, most Java APIs lack both.
Some static analysis tools can use annotations to check whether you're passing a null value inappropriately. For example, the FindBugs tool includes support for these annotations:
#NonNull - The value must not be null
#CheckForNull - The value may contain null.
#Nullable - Whether the value may contain null or not depends on context.
Read the javadocs of the methods you are trying to call. If the javadocs don't specify this, then trial and error in a unit test is probably your best bet.
I'm wondering if it is an accepted practice or not to avoid multiple calls on the same line with respect to possible NPEs, and if so in what circumstances. For example:
anObj.doThatWith(myObj.getThis());
vs
Object o = myObj.getThis();
anObj.doThatWith(o);
The latter is more verbose, but if there is an NPE, you immediately know what is null. However, it also requires creating a name for the variable and more import statements.
So my questions around this are:
Is this problem something worth
designing around? Is it better to go
for the first or second possibility?
Is the creation of a variable name something that would have an effect performance-wise?
Is there a proposal to change the exception
message to be able to determine what
object is null in future versions of
Java ?
Is this problem something worth designing around? Is it better to go for the first or second possibility?
IMO, no. Go for the version of the code that is most readable.
If you get an NPE that you cannot diagnose then modify the code as required. Alternatively, run it using the debugger and use breakpoints and single stepping to find out where the null pointer is coming from.
Is the creation of a variable name something that would have an effect performance-wise?
Adding an extra variable may increase the stack frame size, or may extend the time that some objects remain reachable. But both effects are unlikely to be significant.
Is there a proposal to change the exception message to be able to determine what object is null in future versions of Java ?
Not that I am aware of. Implementing such a feature would probably have significant performance downsides.
The Law of Demeter explicitly says not to do this at all.
If you are sure that getThis() cannot return a null value, the first variant is ok. You can use contract annotations in your code to check such conditions. For instance Parasoft JTest uses an annotation like #post $result != null and flags all methods without the annotation that use the return value without checking.
If the method can return null your code should always use the second variant, and check the return value. Only you can decide what to do if the return value is null, it might be ok, or you might want to log an error:
Object o = getThis();
if (null == o) {
log.error("mymethod: Could not retrieve this");
} else {
o.doThat();
}
Personally I dislike the one-liner code "design pattern", so I side by all those who say to keep your code readable. Although I saw much worse lines of code in existing projects similar to this:
someMap.put(
someObject.getSomeThing().getSomeOtherThing().getKey(),
someObject.getSomeThing().getSomeOtherThing())
I think that no one would argue that this is not the way to write maintainable code.
As for using annotations - unfortunately not all developers use the same IDE and Eclipse users would not benefit from the #Nullable and #NotNull annotations. And without the IDE integration these do not have much benefit (apart from some extra documentation). However I do recommend the assert ability. While it only helps during run-time, it does help to find most NPE causes and has no performance effect, and makes the assumptions your code makes clearer.
If it were me I would change the code to your latter version but I would also add logging (maybe print) statements with a framework like log4j so if something did go wrong I could check the log files to see what was null.