I have following REST endpoint that returns a simple data class with two doubles
#GetMapping("/test")
public LatLng test() {
return new LatLng(-26.733229893125923, -26.733229893125923);
}
My test looks like this:
mockMvc.perform(
get("/test")
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect((jsonPath("$.latitude", is(-26.733229893125923))))
.andExpect((jsonPath("$.longitude", is(-26.733229893125923))));
The test always fails with
java.lang.AssertionError: JSON path "$.latitude" Expected: is
<-26.733229893125923>
but: was <-26.733229893125923>
The stacktrace correctly shows them being the same values but the test still failed for some reason.
If I reduce the double precision by one the test works. The test also fails if I use Matchers.closeTo(-26.733229893125923, 0.01)
The stacktrace correctly shows them being the same values but the test still failed for some reason.
That actually shows that their string representations (i.e., the result of invoking toString() on the objects) are the same. It does not show that the objects are equal in terms of .equals() semantics.
Thus, the expected object is likely a Double; whereas, the actual object is likely a Float.
If that's the case, the following should likely make your test pass.
.andExpect(jsonPath("$.latitude", is(-26.733229893125923f)))
If you're using Spring 4.3.15 or newer, you should be able to use the following as well.
.andExpect(jsonPath("$.latitude").value(is(-26.733229893125923), Double.class))
Related
I'm testing my coroutine functions in my Kotlin Multiplatform project. I've mocked out the implementation behind them, so no actual await occurs during tests.
Consider the following test, curated from the test README:
#Test fun testAsyncFunction() = runBlocking {
val result: List<myClass> = myService.someSuspendFunction()
assertEquals(result.first()?.name, "name")
assertNotNull(result.first()?.someRequiredValue)
}
The second assertion has a return type of T, which causes its result to be returned to the runBlocking function, throwing the following error:
Invalid test class 'com.example.shared.core.service.ExampleTests':
1. Method testAsyncFunction() should be void
I've found 2 solutions to this, either I can swap the two assertions around (assertEquals has a Unit return type, thus no issues), or write val ignored = assertNotNull(result.first()?.someRequiredValue). However neither of these two solutions are ideal, as I'll either have extraneous code that my IDE is warning me to remove, or my assertions are out of order.
What is the best solution to this issue?
The problem is that the method is inferring the return type from runBlocking, which returns value from the inner suspending function.
You can force it to generate a void return type by specifying the return type : Unit explicitly rather than rely on the inferred value.
I am trying to use Optional instead of standard null checks in java
#Data
public class InputObj {
private Double savings;
}
#Data
public class Result {
private String outputSavings;
}
public Result convertInputObjToResult(InputObj inputObj){
Result result = new Result();
Optional<InputObj> optionalInputObj = Optional.ofNullable(inputObj);
optionalInputObj.map(InputObj::getSavings).map(value -> util.convertRoundAndAbs(value,true)).ifPresent(result::setOutputSavings);
return result;
}
which is equivalent of below
public Result convertInputObjToResult(InputObj inputObj){
Result result = new Result();
if(inputObj != null){
if(inputObj.getSavings() != null){
result.setOutputSavings(util.convertRoundAndAbs(inputObj.getSavings(),true));
}
}
return result;
}
I wrote some test cases and I do not get any Null Pointer Exception but I am unable to understand that ifPresent condition is at end and map is before but still I don't get any NPE. Do you see any thing wrong with this code or how it can be improved? This is part of a spring boot application and #Data annotation is used for lombok.
Here's a link to further describe how the map operation works for the Java Optional class.
If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. Otherwise return an empty Optional.
So in a case where you have a null value from the map method, it will automatically be converted to Optional.empty().
Then, taking a look at the ifPresent method
If a value is present, invoke the specified consumer with the value, otherwise do nothing.
So this is why you aren't getting any NPE's; the map operations are able to map null results or passed values to Optional.empty(), and the ifPresent operation doesn't execute if passed an empty Optional.
There is no issue with the code except for the typo “ optionalMembershipDetails”. Assuming you meant to use “ optionalInputObj”.
You need to read about java streams to understand the full concept. In a nutshell, operations are evaluated in lazy manner. So ifPresent call will trigger operations which appear before it. In this case, the object is wrapped inside optional, so each intermediate operation will pass another optional to the next operation. Having Optional prevents you getting NPE.
I have the following code that is inside of a method that I am testing. I need to mock this restTemplate call to get predictable result.
GitHubEmail[] gitHubEmails = restTemplate
.getForObject(userEmailsUrl, GitHubEmail[].class, oAuthToken);
In the test method, I do this:
RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
GitHubEmail fakeGitHubEmail = new GitHubEmail("testemail#email.com",
false, false, GitHubEmailVisibility.PRIVATE);
GitHubEmail[] fakeEmails = {fakeGitHubEmail};
Mockito.when(mockRestTemplate.getForObject(
Mockito.eq(userUrl),
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)))
.thenReturn(fakeEmails);
gitHubService.setRestTemplate(mockRestTemplate);
User user = gitHubService.getUser(testOAuthToken);
Things aren't working as I expect them to... When I examine gitHubEmails variable in my method I am testing, it's null.
Why isn't this working?
The current code as it is right now does not contain any mistakes. However, there are two things we don't see from the given code:
We don't see that testOAuthToken is properly passed to the oAuthToken variable within the githubService.
We don't see that the userUrl is passed to the userEmailsUrl within githubService.
You should make sure that all properties match the one you expect them to be, otherwise the mocking doesn't work. Given that you named one property userUrl and the other one userEmailsUrl, it's likely that the error is there.
Usually, when I encounter these error-prone mocking situations, I use "any matchers" (any(), anyString(), ...) when mocking and then after the call and the assertions, I use Mockito.verify() to check if the parameters match:
Mockito.when(mockRestTemplate.getForObject(
Mockito.anyString(), // Use anyString()
Mockito.eq(GitHubEmail[].class),
Mockito.anyString())) // Use anyString()
.thenReturn(fakeEmails);
// Call + Assertions ...
Mockito.verify(mockRestTemplate).getForObject(
Mockito.eq(userUrl), // Use eq()
Mockito.eq(GitHubEmail[].class),
Mockito.eq(testOAuthToken)); // Use eq()
The reason for this is that the verify() output gives a lot more feedback. Rather than just failing, it will tell why it failed when:
The mocked method was called with different arguments, and which arguments
The mocked object had different methods being invoked
Grails has a bug with regards to databinding in that it throws a cast exception when you're dealing with bad numerical input. JIRA: http://jira.grails.org/browse/GRAILS-6766
To fix this I've written the following code to manually handle the numerical input on the POGO class Foo located in src/groovy
void setPrice(String priceStr)
{
this.priceString = priceStr
// Remove $ and ,
priceStr = priceStr.trim().replaceAll(java.util.regex.Matcher.quoteReplacement('$'),'').replaceAll(',','')
if (!priceStr.isDouble()) {
errors.reject(
'trade.price.invalidformat',
[priceString] as Object[],
'Price:[{0}] is an invalid price.')
errors.rejectValue(
'price',
'trade.price.invalidformat')
} else {
this.price = priceStr.toDouble();
}
}
The following throws a null reference exception on the errors.reject() line.
foo.price = "asdf" // throws null reference on errors.reject()
foo.validate()
However, I can say:
foo.validate()
foo.price = "asdf" // no Null exception
foo.hasErrors() // false
foo.validate()
foo.hasErrors() // true
Where does errors come from when validate() is called?
Is there a way to add the errors property without calling validate() first?
I can't exactly tell you why, but you need to call getErrors() explicitly instead of accessing it as errors like a property. For some reason, Groovy isn't calling the method for it. So change the reject lines in setPrice() to
getErrors().reject(
'trade.price.invalidformat',
[priceString] as Object[],
'Price:[{0}] is an invalid price.')
getErrors().rejectValue(
'price',
'trade.price.invalidformat')
That is the easiest way to make sure the Errors object exists in your method. You can check out the code that adds the validation related methods to your domain class.
The AST transformation handling #Validateable augments the class with, among other things
a field named errors
public methods getErrors, setErrors, clearErrors and hasErrors
The getErrors method lazily sets the errors field if it hasn't yet been set. So it looks like what's happening is that accesses to errors within the same class are treated as field accesses rather than Java Bean property accesses, and bypassing the lazy initialization.
So the fix appears to be to use getErrors() instead of just errors.
The errors are add to your validateable classes (domain classes and classes that have the annotation #Validateable) dinamically.
Allowing the developer to set a String instead of a number doesn't seem a good way to go. Also, your validation will work only for that particular class.
I think that a better approach is to register a custom property editor for numbers. Here's a example with dates, that enable the transform of String (comming from the form) to Date with a format like dd/MM/yyyy. The idea is the same, as you will enforce that your number is parseable (eg. Integer.parseInt() will throw exception).
In your domain class, use the numeric type instead of String, so by code developers will not be allowed to store not number values.
So I have an abstract data type called RegionModel with a series of values (Region), each mapped to an index. It's possible to remove a number of regions by calling:
regionModel.removeRegions(index, numberOfRegionsToRemove);
My question is what's the best way to handle a call when the index is valid :
(between 0 (inclusive) and the number of Regions in the model (exclusive))
but the numberOfRegionsToRemove is invalid:
(index + regionsToRemove > the number of regions in the model)
Is it best to throw an exception like IllegalArgumentException or just to remove as many Regions as I can (all the regions from index to the end of the model)?
Sub-question: if I throw an exception what's the recommended way to unit test that the call threw the exception and left the model untouched (I'm using Java and JUnit here but I guess this isn't a Java specific question).
Typically, for structures like this, you have a remove method which takes an index and if that index is outside the bounds of the items in the structure, an exception is thrown.
That being said, you should be consistent with whatever that remove method that takes a single index does. If it simply ignores incorrect indexes, then ignore it if your range exceeds (or even starts before) the indexes of the items in your structure.
I agree with Mitchel and casperOne -- an Exception makes the most sense.
As far as unit testing is concerned, JUnit4 allows you to exceptions directly:
http://www.ibm.com/developerworks/java/library/j-junit4.html
You would need only to pass parameters which are guaranteed to cause the exception, and add the correct annotation (#Test(expected=IllegalArgumentException.class)) to the JUnit test method.
Edit: As Tom Martin mentioned, JUnit 4 is a decent-sized step away from JUnit 3. It is, however, possible to also test exceptions using JUnit 3. It's just not as easy.
One of the ways I've tested exceptions is by using a try/catch block within the class itself, and embedding Assert statements within it.
Here's a simple example -- it's not complete (e.g. regionModel is assumed to be instantiated), but it should get the idea across:
public void testRemoveRegionsInvalidInputs() {
int originalSize = regionModel.length();
int index = 0;
int numberOfRegionsToRemove = 1,000; // > than regionModel's current size
try {
regionModel.removeRegions(index, numberOfRegionsToRemove);
// Since the exception will immediately go into the 'catch' block this code will only run if the IllegalArgumentException wasn't thrown
Assert.assertTrue("Exception not Thrown!", false);
}
catch (IllegalArgumentException e) {
Assert.assertTrue("Exception thrown, but regionModel was modified", regionModel.length() == originalSize);
}
catch (Exception e) {
Assert.assertTrue("Incorrect exception thrown", false);
}
}
I would say that an argument such as illegalArgumentException would be the best way to go here. If the calling code was not passing a workable value, you wouldn't necessarily want to trust that they really wanted to remove what it had them do.