Mockito defining 'when' invokes the answer - java

I need to mock a JDBC update statement, and I want to make sure that the update string sent is the correct one. I have a MockConnectionManager that has the following method defined for defining the expected query strings:
public void setUpdateExpectedQuery(String ...expectedQueryStrings) throws SQLException {
Statement mockStatement = mock(Statement.class);
when(mockConnection.createStatement()).thenReturn(mockStatement);
when(mockStatement.executeUpdate(anyString())).then(new Answer<String>() {
#Override
public String answer(InvocationOnMock invocationOnMock) throws Throwable {
String str = Arrays.toString(invocationOnMock.getArguments());
throw new RuntimeException("Update string is not as expected: " + str);
}
});
for(String expected : expectedQueryStrings) {
when(mockStatement.executeUpdate(expected)).then(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
// Do something, just don't throw an exception here.
return null;
}
});
}
}
I want that if an unexpected query string was encountered an exception will be thrown. The query strings we expect are below as mentioned in the Mockito wiki (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#2).
For some reason, when executing the test and just calling the setUpdateExpectedQuery, an exception is thrown.
MockConnectionManager connectionManager = (MockConnectionManager) context.getBean("connectionManager");
connectionManager.setUpdateExpectedQuery("INSERT WHATEVER INTO WHENEVER");
The same exception as written in the first Answer: java.lang.RuntimeException: Update string is not as expected: [INSERT WHATEVER INTO WHENEVER]
How is this possible? is calling 'when' actually invokes the method? I never saw it happening in other cases...

I suspect the problem is that your calls within the loop (when you call mockStatement.executeUpdate(expected)) match your earlier mock of when(mockStatement.executeUpdate(anyString())).
Remember that the way the mock knows what you're calling within the when is because you're calling it - imagine translating when(mockStatement.executeUpdate(anyString())) into:
int result = mockStatement.executeUpdate(anyString());
OngoingStubbing<Integer> tmp = when(result);
tmp.then(...);
It may be that you just need to have a single when(...) call. So:
public void setUpdateExpectedQuery(String ...expectedQueryStrings)
throws SQLException {
final Set<String> capturedQueries = new HashSet<>
(Arrays.asList(expectedQueryStrings);
Statement mockStatement = mock(Statement.class);
when(mockConnection.createStatement()).thenReturn(mockStatement);
when(mockStatement.executeUpdate(anyString())).then(new Answer<String>() {
#Override
public String answer(InvocationOnMock invocationOnMock) throws Throwable {
String query = (String) invocationOnMock.getArguments[0];
if (capturedQueries.contains(query)) {
return null;
}
throw new RuntimeException("Update string is not as expected: " + query);
}
});
}

Related

Testing surrounding try catch method with mockito

Im figuring out, how to test this method and force the exception "DataAccessResourceFailureException", but i didn't have a valid way to do it.
I need to force that exception at "ProductRepositoryImpl" class. Any ideas?
ProductRepositoryImpl
#Override
public Product saveProduct(Product input) {
try {
return productRepositoryAdapter.saveProduct(input);
} catch (DataAccessResourceFailureException e) {
logger.error(ERROR_WHEN_SAVING_PRODUCT_DATA_DETAIL + e.getMessage());
}
return null;
}
ProductRepositoryAdapter
public Product saveProduct(Product input) throws DataAccessResourceFailureException {
ProductData productData = UtilTransform.productToProductData(input);
// This method throws exception when there's no connection
Product createdProduct = productDataRepository.findSkuByCountry(input.getSku(),
input.getCountry());
if (createdProduct == null) {
return Product.fromModel(productDataRepository.save(productData));
} else {
logger.error(THE_PRODUCT_ALREADY_EXISTS_IN_THE_RECORDS);
}
return null;
}
ProductDataRepository
public interface ProductDataRepository extends MongoRepository<ProductData, String> {
#Query("{'sku': ?0, 'country': ?1}")
public Product findSkuByCountry(String sku, String country);
public Optional<ProductData> findById(ProductId id);
}
And my Test, Im using mockito.
#Test
void saveProductException() {
Mockito.when(productRepository.saveProduct(buildProduct())).thenReturn(buildProduct());
Mockito.when(adapter.saveProduct(buildProduct())).
thenThrow(DataAccessResourceFailureException.class);
Assertions.assertThrows(DataAccessResourceFailureException.class,
() -> productRepository.saveProduct(buildProduct()));
}
Error:
org.opentest4j.AssertionFailedError: Expected org.springframework.dao.DataAccessResourceFailureException to be thrown, but nothing was thrown.
EDIT.
I change a little bit my approach, with this code (thanks guys) i was able to throw the exception so my code it will return null. After that checking my jacoco index.html i can see that "exception" its covered successfully.
#Test
void saveProductException() {
Product product = buildProduct();
Mockito.when(adapter.saveProduct(product)).
thenThrow(DataAccessResourceFailureException.class);
Assertions.assertNull(productRepository.saveProduct(product));
}
This seems suspect:
Mockito.when( productRepository.saveProduct(buildProduct()) ).thenReturn(buildProduct());
. . .
Assertions.assertThrows(DataAccessResourceFailureException.class,
() -> productRepository.saveProduct(buildProduct()) );
You're saying, when productRepository.saveProduct(buildProduct()) is called then return buildProduct() but then you assert that when it's called it should throw DataAccessResourceFailureException?
Instead maybe try this:
#Test
void saveProductException() {
// as NicoVanBelle recommends, ensure you're referencing the same product throughout this test
Product product = buildProduct();
Mockito.when(adapter.saveProduct(product).thenThrow(DataAccessResourceFailureException.class);
// Also as NicoVanBelle points out, when your `adapter` throws, `saveProduct` will return `null`
Assertions.assertThat(productRepository.saveProduct(product)).isNull();
}
I suspect 2 things here
You have setup the productRepository.saveProduct to not to throw and then you assert it throw the exception
Assertions.assertThrows(DataAccessResourceFailureException.class, () -> productRepository.saveProduct(buildProduct()));
You are calling buildProduct() which I assume returns the new product but mockito tries to check the argument equality so takeout it as Product myProduct = buildProduct() and use myProduct
#Test
void saveProductException() {
Product myProduct = buildProduct();
Mockito.when(productRepository.saveProduct(myProduct))
.thenThrow(DataAccessResourceFailureException.class);;
Mockito.when(adapter.saveProduct(buildProduct())).
thenThrow(DataAccessResourceFailureException.class);
Assertions.assertThrows(DataAccessResourceFailureException.class,
() -> productRepository.saveProduct(myProduct));
}

java Mockito verify abstract method

i have an issue on verifying a call to method of class under test, using the verify() method it tells that the call is not done to that method, this method is defined as abstract in super class (loadFile(String))
find bellow the code :
public abstract class FileParser {
public Iterator<String> loadFile(FileSettingsToSend fileSetting) {
System.out.println("file before staged");
try {
if(!movFile("staged",fileSetting))
return null;
System.out.println("file after move "+fileSetting.getFile().getAbsolutePath());
boolean isValidFormatFile = fileValidator.checkFileFormat(fileSetting);
if (!isValidFormatFile) {
System.out.println("file format is not valid");
return null;
}
return readBlock(fileSetting);
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
} finally {
}
//return null;
}
public abstract Iterator<String> readBlock(FileSettingsToSend fileSettingsToSend)
throws JsonProcessingException, IOException;
}
public class JsonFileParser extends FileParser {
public final ObjectMapper mapper = new ObjectMapper();
#Autowired
public JsonFileParser(FileValidator jsonFileValidatorService, FileAttributeService fileAttributeService) {
super(jsonFileValidatorService, fileAttributeService);
}
#Override
public Iterator<String> readBlock(FileSettingsToSend fileSetting) throws JsonProcessingException, IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println("inside readBlock json implementation");
List<String> listAttribute = fileAttributeService.getAttributes(fileSetting.getDiretoryPath());
String[] blocDelimitor = fileAttributeService.getDelimitorRepositpry(fileSetting.getDiretoryPath());
System.out.println("after validator");
final JsonNode root = mapper.readTree(fileSetting.getFile());
if (root == null)
return null;
Iterator<JsonNode> nodeIterator = root.elements();
System.out.println("Data is " + root);
return new Iterator<String>() {
JsonNode node;
#Override
public boolean hasNext() {
return nodeIterator.hasNext();
}
#Override
public String next() {
int i = 0;
node = nodeIterator.next();
System.out.println("after nex " + node.toString());
Arrays.stream(blocDelimitor).forEach(e -> {
node = node.path(e);
System.out.println("inside next " + node.toString());
});
String result = null;
if (node.isArray()) {
System.out.println("It is Array");
for (JsonNode node1 : node) {
if (i != 0)
result = result + "," + listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
else
result = listAttribute.stream().map(e -> e + "=" + node1.get(e))
.collect(Collectors.joining(","));
i++;
}
} else
result = listAttribute.stream().map(e -> e + "=" + node.get(e)).collect(Collectors.joining(","));
return result;
}
};
}
Test method is :
#Mock
FileValidator jsonFileValidatorService;
#Mock
FileAttributeService fileAttributeService;
JsonFileParser jsonFileParserMock = new JsonFileParser(jsonFileValidatorService, fileAttributeService);
#Test
public void validatorNotTrue() throws JsonProcessingException, IOException{
when(jsonFileValidatorService.checkFileFormat( anyObject() )).thenReturn(true);
JsonFileParser jsonFileParser = Mockito.spy(jsonFileParserMock);
doReturn(true).when(jsonFileParser).movFile(anyString(),anyObject() );
assertNull(jsonFileParser.loadFile(null));
verify(jsonFileParser, times(1)).movFile(anyString(),anyObject());
assertTrue(jsonFileParser.movFile(anyString(), anyObject()));
assertTrue(jsonFileValidatorService.checkFileFormat( anyObject() ));
//exception.expect(Exception.class);
verify(jsonFileParser,times(1)).readBlock(anyObject();
}
#BeforeClass
public static void settingUp(){
}
#Before
public void initMock(){
MockitoAnnotations.initMocks(this);
}
the line verify(jsonFileParser,times(1)).readBlock(anyObject(); return false; meaning that the method loadFile of jsonfileParser not called
can you get your held to tell why it is not called.
Thank you.
This happens because you initialize the mocks after you create a JsonFileParser. Note that #Before method is executed after all the fields of your test class are initialized.
As a result, you pass null dependencies to the class. The invocation to the null FileValidator throws NullPointerException, but you swallow it in your catch block.
Generally it is advisable to verify the arguments you pass to your constructors and methods, to fail fast in case of an error. For example, Java comes with a handy Objects::requireNonNull method to verify that the passed parameters are non-null.
Similarly it's generally a bad practice to swallow every single exception. For instance, in your example, you expect IOException and JsonProcessingException to be thrown. It's better to catch these explicitly and let the program crash (or at least log a warning) for any other one.
Finally, mocks and spies are prone to overuse. Usually, it's enough to use fakes - dummy implementations of your interfaces. Depending on how much control you have over the code, you may also want to refactor it to avoid using a spy at all. Using one in a code you may freely change may signal an architectural problem.

Getting method regardless of parameters

I am trying to get method regardless of what parameters that method takes (as of now there is no method overloading and there wouldn't be in future). The only possible solution that i could come up with was
private Method getMethod(Class<?> clas, String methodName) {
try {
Method[] methods = clas.getMethods();
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(methodName)) {
return method;
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
What i want to ask that is there a way to fetch a method regardless of its parameters ? I was looking at clas.getMethod ("methodName", parameters) and if i provide null in there it will try to fetch a method which has no parameters. Which wouldn't be no case.
Any ideas ?
EDIT
Thanks guys for input. In my case, i know that there would be only one method regardless of its case. The reason i am using ignoreCase is because the input will be coming from a developer (in other team) and he will be providing the name as a hard-coded string. So to keep things from spilling out of our hands, I am using a safe approach.
No. The way you've done it is the way to go. A method is identified by its signature and the signature includes the name and the parameter types.
Here is a solution that retrieves all methods with the specified class and method name regardless of the method's parameters:
public class Test
{
private class Foo
{
public void bar()
{
}
public void bar(String s)
{
}
public void goo()
{
}
}
private static Method[] getMethods(Class<?> clazz, String methodName)
{
List<Method> methods = new ArrayList<Method>();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod: declaredMethods)
{
if (declaredMethod.getName().equals(methodName))
{
methods.add(declaredMethod);
}
}
return methods.toArray(new Method[methods.size()]);
}
public static void main(String[] args)
{
Method[] methods = getMethods(Foo.class, "bar");
System.out.println(Arrays.toString(methods));
}
}
This generates the following output:
[public void com.example.Test$Foo.bar(java.lang.String), public void com.example.Test$Foo.bar()]
You've done just fine. This is basically the same as the solution to a similar problem I dealt with four years ago, creating a means to create callback methods in Java. The constructors for my Callback class were:
public Callback(Class<?> clazz, String methodName, Object parentObj) {
// Find a method with the matching name
Method[] allMethods;
try { allMethods = clazz.getMethods(); }
catch(SecurityException se) { allMethods = new Method[0]; }
int count = 0;
Method single = null;
for(Method m : allMethods) {
if(m.getName().equals(methodName)) {
single = m;
count++;
}
// Can't have more than one instance
if(count > 1)
throw new IllegalArgumentException(clazz.getName()
+ " has more than one method named " + methodName);
}
if(count == 0) // No instances found
throw new IllegalArgumentException(clazz.getName()
+ " has no method named " + methodName);
this.parentObj = parentObj;
this.method = single;
this.parameters = single.getParameterTypes();
}
public Callback(
Class<?> clazz,
String methodName,
Object parentObj,
Class<?>...parameters)
{
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); }
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
My Callback class isn't really useful any more in the era of Java 8, but at the time the only real means for a "callback" in java was anonymous interface implementations, which wasn't sufficient for my use-case.
As you can see in the first constructor, it throws an exception if it finds multiple methods with the same name.
Using java streams there is a really short method of finding a method, the first match, by its name only:
Stream.of(type.getMethods())
.filter((m) -> m.getName().equals(searchedName))
.findFirst()
.get();
I think this is a short and readable possibility in this case.

avoiding code duplication in a java method

Apologies if this has already been asked/answered a thousand times (I did check first).
I'm not a Java programmer by trade and have been tasked with extending an existing Java SOAP service. I'm keen to avoid copy/pasting existing code that I know works, but was wondering what the best options available in java are.
Essentially I have this method already:
public String methodThatIDontWantToCopyPaste(
#WebParam(name = "a", partName = "a") String paramA,
#WebParam(name = "b", partName = "b") int paramB,
#WebParam(name = "c", partName = "c") int paramC) {
// Validate parameters
if (paramA.isEmpty() ||
0 == paramB ||
0 == paramC) {
return "Invalid request";
}
String response = "";
try {
// Parmaeters OK, build client
/*
lots of generic implementation here
...
XYZ client = ...
...
*/
response = client.specificMethodToHandleABC(paramA, paramB, paramC);
} catch (SOAPException | IOException ex) {
// handling omitted
}
return response;
}
I want to add several new/similar methods, but each will have:
A different set of parameters
A different block of code to validate the parameters (the above code is trivial, but some will be more detailed
A different implementation of the line:
response = client.specificMethodToHandleABC(a, b, c);
i.e. where a different method will be called, with a different set of arguments
I'd normally go for a callback in my usual programming language, but it's a proprietary language and not as powerful as Java, so I wanted to know what the best option was?
In a similar setting, I used callbacks/anonymous classes by calling a method out of every endpoint and passing a callback for every variable part into the method, like the following
public String methodA(final int param1, final String param2) throws Exception {
return this.call(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return param1 != 0 && param2 != null;
}
});
}
public String methodB(final String param1, final String param2) throws Exception {
return this.call(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return param1 != null && param2 != null;
}
});
}
private String call(Callable<Boolean> validationCallable) throws Exception {
// static code similar to all methods
assert validationCallable.call().equals(Boolean.TRUE);
// static code similar to all methods
return ""; // probably result based on another callable
}

Overloading the getCause() method in a throwable object

How would one go about overloading the getCause() method in a throwable object ?
I have the following but it doesn't seem to work as it says that it cannot be overloaded with a string.
public class MyException extends RuntimeException {
String cause;
MyException(String s) {
cause = s;
}
#Overwrite public String getCause() {
return cause;
}
It is illegal to have two methods that only differ in their return type. Suppose someone wrote:
Object obj = myException.getCause();
That is perfectly legal java, and the compiler has no way to figure out if it's the String version or the Throwable version.
Likewise you can't replace the superclass signature since this is also perfectly legal:
Throwable t = new MyException();
Throwable t0 = t.getCause();
//Returns String?!?!?!?
Accepted answer clears the point :
It is illegal to have two methods that only differ in their return
type
But if you have a situation where, getCause() should return the custom cause in MyException, in case original cause is null.
In that case, you can use initCause() to set the cause and override toString() method. So, when getCause() method will be called on object of MyException, it will show the message from customCause instead of null.
What is the use: In legacy system, if you have used getCause() on MyException object while logging, and now you want to add the custom cause to it without changing lot of code, here is the way.
public class MyException extends RuntimeException {
String customCause;
MyException(String s) {
super(s);
customCause = s;
}
#Override
public synchronized Throwable getCause() {
if (super.getCause() != null) {
return this;
} else {
this.initCause(new Throwable(customCause));
return this;
}
}
#Override
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
if (message == null) {
message = customCause;
}
return (message != null) ? (s + ": " + message) : s;
}
}
References:
https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#initCause(java.lang.Throwable)
https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html

Categories