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
Related
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))
What is the difference between
jasmine.createSpy('someMethod')
And
spyOn(someObject, 'someMethod')
And why should one choose to use spyOn?
My guess is that the first alternative will match the method someMethod no matter in what object it's contained but spyOn will only match if it's contained in someObject. Thus making createSpy just a more generic matcher?
The difference is that you should have a method on the object with spyOn
const o = { some(): { console.log('spied') } };
spyOn(o, 'some');
while the mock method is created for your with createSpy():
const o = {};
o.some = jasmine.createSpy('some');
The advantage of the spyOn is that you can call the original method:
spyOn(o, 'some').and.callThrough();
o.some(); // logs 'spied'
And as #estus says the original method is restored after the test in case of spyOn. This should be done manually when it's reassigned with.
Additionally to the other fine answer:
Use spyOn() to spy (intercept) an existing method on an object to track calls of other modules to it.
Use jasmine.createSpy() to create a function that can be passed as callback or Promise handler to track call-backs.
I have a test case like this:
it("test",function(){
var spy = sinon.spy(test,"method");
decider = 1
test.nextServiceTab();
assert(spy.calledOnce);
});
When the method test.nextServiceTab is called, it calls method based on the value decider, which is supposed to be 1. In fact the control goes to the the method.
But why does the control goes to the method? Since I'm spying it should't be right?
My goal was to just check that method is called. Where I'm making mistake?
Is the way I have used sinon is correct?
If you want to avoid control entering the function, you should use sinon.stub instead of sinon.spy. With a stub you can still see if it is called because stub implements the same interface as spy, but additionally it prevents the original function from receiving control and allows you to override the behavior.
For example, if you want the function to always return true:
it("test",function(){
var stub = sinon.stub(test, "method");
stub.returns(true);
decider = 1;
test.nextServiceTab();
assert(stub.calledOnce);
stub.restore();
});
I am using gomock to create mock objects for unit testing. The following gives the mock object a method called GetQuestionById and tells the mock controller to expect the method to be called with argument 1:
gw.EXPECT().GetQuestionById(1)
But how do I specify that the mocked method should return a particular value?
When you call gw.EXPECT().GetQuestionById(1), it ends up calling the method RecordCall on the mock controller. RecordCall returns a Call, and Call has a method called Return that does exactly what you want:
gw.EXPECT().GetQuestionById(1).Return(Question{1, "Foo"})
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.