I need to know how can I mock a method which uses .collect(java 8) method, below is the method
//return data
public String getData(List<Node> nodes)
{
return nodes.stream().map(node->
getService().compare(new Reference()).collect(Collectors.joining(~));
}
protected getService()
{
return service;
}
I can mock service like
#Mock //mocking service
Service service
now how can I mock
getService().compare(new Reference()).collect(Collectors.joining(~));
Compare method returns CompareRef object. I can use PowerMock.
In your case I would recommend to mock the compare() method, not collect().
Because you work with a stream you may have some nodes. To emulate the behaviour with multiply call of compare() with the same Reference object you may try this variant:
final CompareRef expectedCompareRef1 = new CompareRef();
final CompareRef expectedCompareRef2 = new CompareRef();
final CompareRef expectedCompareRef3 = new CompareRef();
when(service.compare(eq(new Reference())).thenReturn(expectedCompareRef1).thenReturn(expectedCompareRef2).thenReturn(expectedCompareRef3);
then call you getData() method:
final List<Nodes> givenNodes = new ArrayList<>();
givenNodes.add(node1);
givenNodes.add(node2);
givenNodes.add(node3);
final String actualResult = myInstance.getData(givenNodes);
Assert.assertEquals("TODO: expectedResult", actualResult);
As result the stream will collect all your test expectedCompareRefN objects.
Note, to have working eq(new Reference()) your Reference class should implement equals/hashCode methods. Otherwise eq(new Reference()) always be false and thenReturn will not return the specified expected objects.
Related
I'm trying to implement the singleton pattern in a database helper class, but, I can't seem to understand the purpose of a factory constructor and if there's an alternative method to using it.
class DbHelper {
final String tblName ='';
final String clmnName ='';
final String clmnPass='';
DbHelper._constr();
static final DbHelper _db = new DbHelper._constr();
factory DbHelper(){ return _db;}
Database _mydb;
Future<Database> get mydb async{
initDb() {
if(_mydb != null)
{
return _mydb;
}
_mydb = await initDb();
return _mydb;
}
There is no need to use the factory constructor.
The factory constructor was convenient when new was not yet optional because then it new MyClass() worked for classes where the constructor returned a new instance every time or where the class returned a cached instance. It was not the callers responsibility to know how and when the object was actually created.
You can change
factory DbHelper(){ return _db;}
to
DbHelper get singleton { return _db;}
and acquire the instance using
var mySingletonReference = DbHelper.singleton;
instead of
var mySingletonReference = DbHelper();
It's just a matter of preference.
I also found this article helpful: https://theburningmonk.com/2013/09/dart-implementing-the-singleton-pattern-with-factory-constructors/
I have read some post about it but nothing solved my problem. I have a class which is singleton and one method of this class is being called inside another class. I need to mock this method call.
Class SingletonClass
{
public static SingletonClass instance()
{
......
return instance;
}
public boolean methodToBeMocked(Object obj)
{
return false;
}
}
And the another class is :
Class A
{
Object doSomeStuff()
{
......
boolean result = SingletonClass.instance.methodToBeMocked();
}
}
And I am mocking the method methodToBeMocked in my test class. I have tried to use doReturn instead of thenReturn as it is suggested in other posts but it did not help.
My test class is :
Class TestClass{
Class A a = new A();
public void test()
{
SingletonClass singletonClass = mock(SingletonClass.class);
doReturn(true).when(singletonClass).methodToBeMocked(any());
a.doSomeStuff(); // here mocked method returns false
// but if I do this below it returns true !!!!
Object obj = new Object();
boolean result = singletonClass.mockedMethod(obj);
}
}
So why I am not getting true when a.doSomeStuff is called ? What is wrong here ?
For the benefit of others, I was using the following mock with the expectation it would not call someMock.someMethod(), unlike the when(someMock.someMethod()).doReturn("someString") usage.
Mockito.doReturn("someString").when(someMock).someMethod();
I could not understand why the real someMethod() was still being called. It turns out the method was specified as final. Mockito can't mock static or final methods.
The problem is the static method public static SingletonClass instance(). The standard mockito library does not support mocking of static methods. I seen two solutions.
You can rewrite small your code as:
Add new method getSingletonClassInstance() to be mocked in test
Class A {
Object doSomeStuff()
{
......
boolean result = getSingletonClassInstance();
}
SingletonClass getSingletonClassInstance(){
return SingletonClass.instance.methodToBeMocked();
}
}
use spy from mockito library to create an instance of Class A
import static org.mockito.Mockito.spy;
.....
Class TestClass{
public void test()
{
Class A a = spy(new A());
SingletonClass singletonClass = mock(SingletonClass.class);
doReturn(true).when(singletonClass).methodToBeMocked(any());
doReturn(singletonClass).when(a).getSingletonClassInstance();
a.doSomeStuff(); // here mocked method returns false
// but if I do this below it returns true !!!!
Object obj = new Object();
boolean result = singletonClass.mockedMethod(obj);
}
}
More information about the spy in mockito. Spy used real instance and invoke real method but provide a functionality to mock specific method. Don't worry about the others method they will continue to work with real implementation, only mocked method will be affected.
You can use power mockito to mock the public static SingletonClass
instance()
In my spring boot service, I'm using https://github.com/java-json-tools/json-patch for handling PATCH requests.
Everything seems to be ok except a way to avoid modifying immutable fields like object id's, creation_time etc. I have found a similar question on Github https://github.com/java-json-tools/json-patch/issues/21 for which I could not find the right example.
This blog seems to give some interesting solutions about validating JSON patch requests with a solution in node.js. Would be good to know if something similar in JAVA is already there.
Under many circumstances you can just patch an intermediate object which only has fields that the user can write to. After that you could quite easily map the intermediate object to your entity, using some object mapper or just manually.
The downside of this is that if you have a requirement that fields must be explicitly nullable, you won’t know if the patch object set a field to null explicitly or if it was never present in the patch.
What you can do too is abuse Optionals for this, e.g.
public class ProjectPatchDTO {
private Optional<#NotBlank String> name;
private Optional<String> description;
}
Although Optionals were not intended to be used like this, it's the most straightforward way to implement patch operations while maintaining a typed input. When the optional field is null, it was never passed from the client. When the optional is not present, that means the client has set the value to null.
Instead of receiving a JsonPatch directly from the client, define a DTO to handle the validation and then you will later convert the DTO instance to a JsonPatch.
Say you want to update a user of instance User.class, you can define a DTO such as:
public class UserDTO {
#Email(message = "The provided email is invalid")
private String username;
#Size(min = 2, max = 10, message = "firstname should have at least 2 and a maximum of 10 characters")
private String firstName;
#Size(min = 2, max = 10, message = "firstname should have at least 2 and a maximum of 10 characters")
private String lastName;
#Override
public String toString() {
return new Gson().toJson(this);
}
//getters and setters
}
The custom toString method ensures that fields that are not included in the update request are not prefilled with null values.
Your PATCH request can be as follows(For simplicity, I didn't cater for Exceptions)
#PatchMapping("/{id}")
ResponseEntity<Object> updateUser(#RequestBody #Valid UserDTO request,
#PathVariable String id) throws ParseException, IOException, JsonPatchException {
User oldUser = userRepository.findById(id);
String detailsToUpdate = request.toString();
User newUser = applyPatchToUser(detailsToUpdate, oldUser);
userRepository.save(newUser);
return userService.updateUser(request, id);
}
The following method returns the patched User which is updated above in the controller.
private User applyPatchToUser(String detailsToUpdate, User oldUser) throws IOException, JsonPatchException {
ObjectMapper objectMapper = new ObjectMapper();
// Parse the patch to JsonNode
JsonNode patchNode = objectMapper.readTree(detailsToUpdate);
// Create the patch
JsonMergePatch patch = JsonMergePatch.fromJson(patchNode);
// Convert the original object to JsonNode
JsonNode originalObjNode = objectMapper.valueToTree(oldUser);
// Apply the patch
TreeNode patchedObjNode = patch.apply(originalObjNode);
// Convert the patched node to an updated obj
return objectMapper.treeToValue(patchedObjNode, User.class);
}
Another solution would be to imperatively deserialize and validate the request body.
So your example DTO might look like this:
public class CatDto {
#NotBlank
private String name;
#Min(0)
#Max(100)
private int laziness;
#Max(3)
private int purringVolume;
}
And your controller can be something like this:
#RestController
#RequestMapping("/api/cats")
#io.swagger.v3.oas.annotations.parameters.RequestBody(
content = #Content(schema = #Schema(implementation = CatDto.class)))
// ^^ this passes your CatDto model to swagger (you must use springdoc to get it to work!)
public class CatController {
#Autowired
SmartValidator validator; // we'll use this to validate our request
#PatchMapping(path = "/{id}", consumes = "application/json")
public ResponseEntity<String> updateCat(
#PathVariable String id,
#RequestBody Map<String, Object> body
// ^^ no Valid annotation, no declarative DTO binding here!
) throws MethodArgumentNotValidException {
CatDto catDto = new CatDto();
WebDataBinder binder = new WebDataBinder(catDto);
BindingResult bindingResult = binder.getBindingResult();
binder.bind(new MutablePropertyValues(body));
// ^^ imperatively bind to DTO
body.forEach((k, v) -> validator.validateValue(CatDto.class, k, v, bindingResult));
// ^^ imperatively validate user input
if (bindingResult.hasErrors()) {
throw new MethodArgumentNotValidException(null, bindingResult);
// ^^ this can be handled by your regular exception handler
}
// Here you can do normal stuff with your cat DTO.
// Map it to cat model, send to cat service, whatever.
return ResponseEntity.ok("cat updated");
}
}
No need for Optional's, no extra dependencies, your normal validation just works, your swagger looks good. The only problem is, you don't get proper merge patch on nested objects, but in many use cases that's not even required.
public enum SPHttpClient {
;
private static fun(clientInstance) {
HttpPost postRequest;
/* some processing*/
clientInstance.execute(postRequest);
// I need to mock this execute statement
}
}
Writing Junit test on private method fun,
How to invoke private method which is in ENUM type and also I need to mock clientInstance which is passed through argument of private method??
SPHttpClient spHttpClient;
final Method method = spHttpClient.getClass().getDeclaredMethod("fun", HttpClient.class);
method.setAccessible(true);
Object actual = method.invoke(spHttpClient, mockHttpClient);
I think getclass wont work for enums ??
The signature of invoke is invoke(Object obj, Object... args). obj has to be the this-Object. Since your method is static, there is no this object, you may pass null, but you must not omit it, i.e. following works:
final Method method = SpHttpClient.class.getDeclaredMethod("fun", HttpClient.class);
method.setAccessible(true);
Object actual = method.invoke(null, mockHttpClient);
I want to test following code with Mockito:
public static String funcToTest(String query) throws Exception {
String url = Config.getURL(serviceName);
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
String resultantString= "";
method.setQueryString(URIUtil.encodeQuery(query));
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
Reader reader = new InputStreamReader(method
.getResponseBodyAsStream());
int charValue = 0;
StringBuffer sb = new StringBuffer(1024);
while ((charValue = reader.read()) != -1) {
sb.append((char) charValue);
}
resultantString = sb.toString();
}
method.releaseConnection();
return resultantString;
}
I created the test like following:
#Test
public void testFunc() throws Exception{
HttpMethod method = Mockito.mock(HttpMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
Reader reader = Mockito.mock(Reader.class);
when(method.getResponseBodyAsStream()).thenReturn(inputStream);
PowerMockito.whenNew(Reader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int)'1', -1);
String actualResult = cls.funcToTest("");
String expected = "1";
assertEquals(expected, actualResult);
}
But the reader.read() method is not returning 1. Instead it always returns -1. How should I mock Reader so that read() method will return something else other than -1.
Thanks.
First of all , your test code is doing lots of .class mocking to mock function local variables / references. Mocking is for class dependencies and not for function local variables.
As written, you can't test your function funcToTest with mocking alone. You need to rewrite this function if not willing to use real objects for - HttpMethod & Reader.
You need to remove object creation code with new outside this function if you wish to mock calls on those objects and replace code of new with this get method. e.g.
protected HttpMethod getHttpMethod(String Url){
return new GetMethod(url);
}
Also, I don't see you mocking this line for a fake URL - it seems necessary for unit testing.
String url = Config.getURL(serviceName);
After taking object creation code outside your function, you need to create a new class than extends your SUT ( Subject Under Test ) and you override these methods ( getHttpMethod) to provide fake/mocked instances.
You need to write similar method to get Reader instance.
Then you test this new class - extended from your SUT since object creation logic need not to be tested.
Without taking object creation code outside the function, I don't see a way of mocking it by mockito.
Hope it helps !!
It must work, I'm sorry what make you slightly confused )
// annotations is very important, cls I your tested class name, i assume cls is yours
#RunWith(PowerMockRunner.class)
#PrepareForTest({cls.class})
public class PrinterTest {
#Test
public void print() throws Exception {
String url = "";
GetMethod method = Mockito.mock(GetMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
InputStreamReader reader = Mockito.mock(InputStreamReader.class);
Mockito.when(method.getResponseBodyAsStream()).thenReturn(inputStream);
//forgot about it )
PowerMockito.whenNew(GetMethod.class).withArguments(eq(url)).thenReturn(method);
PowerMockito.whenNew(InputStreamReader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int) '1', -1);
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String actualResult = cls.funcToTest(url);
String expected = "1";
assertEquals(expected, actualResult);
}
}