Let's say you have a method like (Java):
private @Nonnull Optional<Thing> findByIdentifier(Integer thingIdentifier) {
// More logic here
return Optional.of(new Thing());
}
There are two assumptions:
thingIdentifier is a valid number (not null in Java)thingIdentifier is non-negativeCalling the method with null or a negative number makes no sense. The caller should never do this.
My two questions:
How would you deal with this?
assert (debug-only)Optional.EMPTY or nullWould you unit-test such a path for findByIdentifier?
I'm especially conflicted about the unit test, because:
findByIdentifier (but in the calling code).To some extent this applies to other languages. But I think Java is a good example, because:
null in many cases.PositiveInteger (or Identifier<Thing>) type is not as viable because there is no operator overloading.Semantically, testing that method with positive object or null input parameter would not make sense but if you look from that function's behaviour standpoint, both input parameters creates a different use-case regardless of the output.
I would handle this through custom exceptions like ValidationException and except to throw for a specific set of input parameter. Infact, Java has built-in Objects class consisting of static validation methods for input parameters.
Although Optional type may indicate to have two possible results(i.e., null/non-null result) yet it is supportive only from convenience's standpoint; i.e, to avoid null and handling alternate situations during development but does not imply any different meaning from the function's behaviour standpoint because, Ideally, you should never be in a situation where for the same input parameter, you'd have to test two different behaviours just because you have Optional return type.
I would go for Design by Contract. So we can define the rulesets outside of the function and just test against the contracts. Just less noise (not really the question you asked though)
Or in case of testing, i personally do generative testing (that's how I call it) haskell calls it book.realworldhaskell.org/read/testing-and-qualit…
also not really the question you asked.
it's more of an integration test than a unitest unless you test the findThing contracts by I -> O if O can be N variants of O for example. so if the thing accessed for behaviour below is an abstraction that gets injected it could make sense to test our membrane / intent.
Besides that it's an blackbox test where we just check contracts and the behaviour of our blackbox in combination of our intent.
But I guess you already thought this through. To me this is a curious questions as well. I wrote an ORM and since an ORM is very very abstract the abstraction tests are very exhaustive and without complete inversion of control to some degree questionable since they IO can have a multitude of side effects and testing derived state against an intent of state is a pain in the ass to maintain (simple put to what i mean -> using static outcome will make you have a n^k variance since all types of states have to be tested which is easy in simple cases but as soon as we got the factors combined testing against all of this getting harder
I talked with a friend of mine and he's a fan of upper / lower boundary tests in such cases .... again I am rambling :) I have no real answer since this is a lot about design and usecase and accessibility and complexity.
But I love to hear you or other conclusions to this topic :).
Matthew Cory
Tagline not found.
Since it's a private method I wouldn't worry about verification within it. That should be ensured before the method gets called, where ever the value comes from. Since you're likely getting the value from an external source - public methods parameter, or a file, or another db call - definitely validate it there.
As for testing it, if you have complete coverage of your public methods that call this, it'll get covered (and any paths inside it as well). If it isn't getting correctly covered, then either you don't have full coverage on your public methods or it's not getting used and scrap it.