Code:
public class AccountService(){
private ObjectMapper mapper = new ObjectMapper();
public Account getAccount(){
try {
ClientResponse response = RestUtility.getAccounts();
if(CLientResponse.OK.Status == response.getClientResponseStatus()){
return mapper.readValue(response.getEntity(String.class), Account.class)
}
} catch(Exception e){
log.error(e.getMessage(), e);
}
return null;
}
}
How can I mock this service? The RestUtility is a static utility and cannot be mocked by mockito. All I want is for my method to return a list of 'mock' accounts. Is it even possible with this architecture?
To mock statick method you cna use PowerMock.
Or you can create wrapper on your RestUtility class.
Reference to this wrapper should be provided on constructor.
If you change to
public class AccountService() {
protected ClientResponse getResponse() { return RestUtility.getAccounts(); }
public Account getAccount() {
try {
ClientResponse response = getResponse();
...
}
}
it is trivial to mock out getResponse() using Mockito or other mock frameworks. Or even easier:
public class AccountServiceTest {
class TestableAccountService extends AccountService {
#Override
protected ClientResponse getResponse() { return <yourmockresponsegoeshere>; }
}
#Test
public void testMe() {
AccountService ac = new TestableAccountService();
assertThat( ac.getAccount.size() , equalTo( 1 ) );
// etc
...
}
Cheers,
Related
I don't know how to create the unit test for my controller with Delete Method.
//Controller class
#PostMapping("delete")
public ResponseEntity<Void> deleteClient(#RequestBody DeleteClientModel deleteClientModel){
clientService.deleteClientById(deleteClientModel.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
//Service class
public void deleteClientById(int id) {
clientRepository.deleteById(id);
}
As you can see the method doesn't return anything so that's why I don't know how to test the controller class. Please help me
Here's a test
#Test
public void ClientController_deleteClient() throws Exception{
???
}
You can use MockMvcRequestBuilder to run controller tests in springboot as below
include the gradle dependency,
testCompile('org.springframework.boot:spring-boot-starter-test')
#WebMvcTest(ClientController.class)
public class TestClientController {
#Autowired
private MockMvc mvc;
#Test
public void ClientController_deleteClient() throws Exception
{
DeleteClientModel deleteClientModel = new DeleteClientModel();
deleteClientModel.setId("100");
mvc.perform( MockMvcRequestBuilders
.post("/delete")
.content(asJsonString(deleteClientModel))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Hope this helped :)
I want to mock Order array class Order[].class. below mockMapper reads Order[].class and need to return Order[].class.
Service class
public class OrdersConnectorImpl {
public Order getOrderById(String Id, OrderType orderType) throws Exception {
Response response = null;
response = orderServiceTarget.queryParam("ID", Id).queryParam(ORDER_TYPE, orderType).request().accept(MediaType.APPLICATION_JSON)
.get();
final StatusType responseStatus = response.getStatusInfo();
final String serverResponseStr = response.readEntity(String.class);
if (responseStatus.equals(Response.Status.OK)) {
objectMapper = getObjectMapper(); // we have a private method in this class
Order[] orders = objectMapper.readValue(serverResponseStr, Order[].class);
if(orders.length>0) {
return orders[0];
}
}
}
}
Test class
public class OrdersConnectorImplTest {
private ObjectMapper mockMapper;
private class MockOrdersConnectorImpl extends OrdersConnectorImpl {
#Override
protected ObjectMapper getObjectMapper() {
return mockMapper;
}
}
}
#Test
public void test_getRenewalOrderForContract() throws Exception {
Response mockResponse = mock(javax.ws.rs.core.Response.class);
Order mockOrder = mock(Order.class);
when(mockResponse.getStatusInfo()).thenReturn(Status.OK);
when(mockResponse.readEntity(String.class)).thenReturn("{}");
when(mockBuilder.get()).thenReturn(mockResponse);
when(mockMapper.readValue("{}", Order[].class)).thenReturn(mockOrder); // this is the problem line
orderConnector.getOrderById("id", OrderType.NEW);
}
}
Please correct me here how to return expected.
You have autowired mockMapper which means, the actual object of ObjectMapper will be injected.
And in the when part, you setting up the behavior of mockMapper, which shouldn't be the case.
Edit 1
In your case, there is no need for mocking the Order class, you have to return the array Order which you can create in the tests.
For your information, with Junit there is no way, you can mock the object which is been created inside the method.
I want to test a method which returns an Optional client in it.
I want to test the scenario when client is empty.This is not a working code but overall it looks like this
public Optional<String> doSomething(String place) {
Optional<Client> client = Optional.empty();
try {
client = Optional.ofNullable(clientHelper.get(place));
} catch (Ex ex) {
log.warn("Exception occured:", ex);
}
return client.isPresent() ? Optional.ofNullable(client.get().getPlaceDetails(place)) : Optional.empty();
}
I have a helper class clientHelper which returns a client based on place if exists, if not it throws exception.
For test, this is what I came up with
#Test
public void testClientHelper(){
ClientHelper clientHelper = Mockito.mock(ClientHelper.class);
Optional<Client> client = Optional.empty();
Mockito.when(Optional.ofNullable(clientHelper.get("IN"))).thenReturn(client);
assertEquals( doSomething("IN"), Optional.empty())
}
But it returns exception -
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Optional cannot be returned by get()
get() should return Client
I have been following this link Mockito error with method that returns Optional<T>
your problem here is that you are calling when with something that isn't a mock. You are passing it an Optional.
If I understand what you are trying to do here, the clientHelper is passed to the object with the doSomething method and you want to mock it for testing purposes. If that's the case it'd more typically look like this:
interface ClientHelper {
Client get(String place) throws Ex;
}
class ClassUnderTest {
private final ClientHelper clientHelper;
public ClassUnderTest(ClientHelper helper) {
this.clientHelper = helper;
}
public Optional<String> doSomething(String place) {
try {
return Optional.ofNullable(clientHelper.get(place).getPlaceDetails(place));
} catch (Ex ex) {
log.warn("Exception: " + ex);
return Optional.empty();
}
}
}
#Test
void testFullHelper() {
Client client = mock(Client.class);
when(client.getPlaceDetails("IN")).thenReturn("Details");
ClientHelper helper = mock(ClientHelper.class);
when(helper.get("IN")).thenReturn(client);
ClassUnderTest obj = new ClassUnderTest(helper);
assertEquals("Details", obj.doSomething("IN"));
}
I am trying to mock a method of a private field that has a return type of void. In my test, I am trying to mock aClass.doSomething() to throw an IllegalStateException and I need to verify that recover() is called. Here is an example:
public class ClassToTest implements Runnable {
private ClassToMock aClass;
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover(){
logger.info("I am recovering");
}
}
I have done each piece separately:
Mock a method call of a private field
Mock a method that has void return type
Throw exception
Verify a private method call
but I wasn't able to put all together. Any help is appreciated
I thought I'd elaborate GhostCat's comments:
Stay with Mockito
Mockito is more than a mocking framework - it's a discipline. If you read carefully the documentation for Mockito and restrain yourself from resorting to PowerMock et al you will learn good OOP practice.
Read how to do dependency injection with constructors
Primum non nocere - first refactor your code like this:
public class ClassToTest implements Runnable {
private final ClassToMock aClass;
private final Logger logger;
//injection of collaborators through the constructor
public ClassToTest(ClassToMock aClass, Logger logger) {
this.aClass = aClass;
this.logger = logger;
}
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover() { //there is no need for this method to be public - see Effective Java item 13
logger.info("I am recovering");
}
}
Now your code is testable using Mockito without resorting to more complex mocking frameworks:
//mocks
#Mock ClassToMock classToMock;
#Mock Logger mockLogger;
//system under test
ClassToTest classToTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks();
classToTest = new ClassToTest(classToMock, mockLogger);
}
#Test
public void whenRun_thenDoesSomethingWithSomeParameter() {
//act
classToTest.run();
//assert
verify(classToMock).doSomething(eq("some parameter"));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsError() {
//arrange
IllegalStateException e = new IllegalStateException();
when(classToMock.doSomething(anyString()).thenThrow(e);
//act
classToTest.run();
//assert
verify(mockLogger).error(eq("Something bad happened"), same(e));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsRecovery() {
//arrange
when(classToMock.doSomething(anyString()).thenThrow(new IllegalStateException());
//act
classToTest.run();
//assert
verify(mockLogger).info(eq("I am recovering"));
}
this question was asked many times but I couldn't find elegant workaround for it.
This example works as desired:
public class RequestWrapper<T> {
private final T request;
private final Class<T> type;
public RequestWrapper(T request, Class<T> type) {
this.request = request;
this.type = type;
}
public T getRequest() {
return request;
}
public Class<T> getType() {
return type;
}
}
public class Service {
private void invoke(String request) {
System.out.println("String:" + request);
}
private void invoke(Object request) {
System.out.println("Object:" + request + "," + request.getClass().getSimpleName());
}
public static void main(String[] args) {
RequestWrapper<String> sw = new RequestWrapper<String>("A", String.class);
RequestWrapper<Integer> iw = new RequestWrapper<Integer>(Integer.valueOf(0), Integer.class);
new Service().invoke(sw.getRequest());
new Service().invoke(iw.getRequest());
}
}
But I would need to add one more method to Service class which do something before/after call of invoke method:
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
invoke(wrapper.getType().cast(wrapper.getRequest()));
invoke(wrapper.getRequest());
} catch(Exception e ) {
// ...
}
}
then the main method would contain:
new Service().invoke(sw);
I understand the reason why the invoke(Object request) is used instead of invoke(String request).
What would be an elegant solution to call proper invoke method and be able to do some common actions before/after it?
To have an interface e.g. Invoker, implement it e.g. StringInvoker, Invoker> and call map.get(wrapper.getType()).invoke(wrapper.getRequest()) is possible solution but I expect something better.
You can check the type and explicitly cast it, for example (I also added Integer so you can see branching on more types):
Class<?> c = wrapper.getType();
if (c == String.class)
invoke((String) wrapper.getRequest()); // Invokes invoke(String)
else if (c == Integer.class)
invoke((Integer) wrapper.getRequest()); // Invokes invoke(Integer)
else
invoke(wrapper.getRequest()); // Invokes invoke(Object)
Note:
If you go on this path, you don't even need to store the request type in the RequestWrapper class because you can just as easily use the instanceof operator on the request itself to check its type. And if you "get rid" of the request type, your current RequestWrapper class will only contain the request so the RequestWrapper is not even needed in this case.
Visitor patter can serves to solve it. Only drawback is that there isn't possible to write:
new Service().invoke(new RequestWrapper<String>("A"));
My implementation:
public class Service {
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
wrapper.invoke(this);
} catch(Exception e ) {
// ...
}
}
public void invoke(String request) {
System.out.println("String:" + request);
}
public void invoke(Boolean request) {
System.out.println("Boolean:" + request);
}
public static void main(String[] args) {
RequestWrapper<Boolean> rw = new BooleanRequestWrapper(Boolean.TRUE);
new Service().invoke(rw);
}
}
abstract class RequestWrapper<T> {
protected final T request;
public RequestWrapper(T request) {
this.request = request;
}
public abstract void invoke(Service v);
}
class BooleanRequestWrapper extends RequestWrapper<Boolean> {
public BooleanRequestWrapper(Boolean request) {
super(request);
}
public void invoke(Service service) {
service.invoke(request);
}
}