here is my code, AgentRest is not mocked in A class
class A {
public void t() throws IOException {
AgentRest agentRest = new AgentRest("127.0.0.1", 8888);
HttpResponse<TaskStatusResponse> a = agentRest.dataBackup(null); // not mock
}
}
#Slf4j
#PrepareForTest({A.class, SftpClientTest.class,AgentRest.class })
#RunWith(PowerMockRunner.class)
class SftpClientTest {
#Test
void getHome() throws Exception {
HttpResponse<TaskStatusResponse> httpResponse =
HttpResponse.<TaskStatusResponse>builder().code(0).body(TaskStatusResponse.builder().status("").build()).build();
AgentRest agentRest = PowerMockito.mock(AgentRest.class);
PowerMockito.whenNew(AgentRest.class).withAnyArguments().thenReturn(agentRest);
PowerMockito.when(agentRest.dataBackup(ArgumentMatchers.any())).thenReturn(httpResponse);
new A().t();
log.info("");
}
}
i have try a lot but still failed, PowerMockito.whenNew seams not working, and i have added all class to PrepareForTest
I have found the probelm is junit5 is not working with powermock, solution link: https://rieckpil.de/mock-java-constructors-and-their-object-creation-with-mockito/
here is my new code:
class A {
public void t() throws IOException {
AgentRest agentRest = new AgentRest("127.0.0.1", 8888);
HttpResponse<TaskStatusResponse> a = agentRest.dataBackup(null);
}
}
#Slf4j
class SftpClientTest {
#Test
void getHome() throws Exception {
try (MockedConstruction<AgentRest> mocked = mockConstruction(AgentRest.class)) {
HttpResponse<TaskStatusResponse> httpResponse =
HttpResponse.<TaskStatusResponse>builder().code(0).body(TaskStatusResponse.builder().status("").build()).build();
// every object creation is returning a mock from now on
AgentRest agentRest = new AgentRest("sa", 22);
when(agentRest.dataBackup(ArgumentMatchers.any())).thenReturn(httpResponse);
new A().t();
}
}
}
Related
I have an interface defined as follows:
public interface HttpClient {
public <T> UdemyResponse<T> get(Request request,
JSONUnmarshaler<T> unmarshaller, Gson gson)
throws UdemyException, IOException;
}
I have a class that implements the interface:
public class OkHttp implements HttpClient {
public OkHttpClient client;
final Logger logger = LoggerFactory.getLogger(getClass());
public OkHttp() {
this.client = new OkHttpClient();
}
#Override
public <T> UdemyResponse<T> get(Request request, JSONUnmarshaler<T> unmarshaller, Gson gson)
throws UdemyException, IOException {
int status_code = 0;
String next = null;
String rawJSON = null;
JsonElement jsonelement = null;
Boolean retry = true;
int attempts = 3;
while ((attempts >= 0) && (retry) && status_code != 200) {
try {
Response response = this.client.newCall(request).execute();
rawJSON = response.body().string();
jsonelement = gson.fromJson(rawJSON, JsonElement.class);
next = gson.fromJson(jsonelement.getAsJsonObject().get("next"), String.class);
status_code = response.code();
if (status_code == 401) {
try {
logger.warn("token expired");
TimeUnit.SECONDS.sleep(5);
retry = true;
continue;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if ((status_code / 100) == 5) {
logger.warn("gateway error");
retry = true;
continue;
}
} catch (IOException e) {
e.printStackTrace();
// this exception will be propagated to the main method and handled there to exit the program,
// this exception should end the program.
throw e;
}
attempts -= 1;
retry = false;
}
if (status_code != 200) {
throw new UdemyException();
}
return new UdemyResponse<T>(status_code, next, rawJSON,
unmarshaller.fromJSON(gson, jsonelement.getAsJsonObject()));
}
If I mock my interface I can write test cases for get() method but my get() method uses the this.client and I need to mock that object as well.
In this case, is it better to mock the OkHttp object rather than the interface?
If you are attempting to test get() then you should not mock that method, if you do, what is it that you are testing? You need to mock the other dependencies of get() to help you test it in isolation. In this case if this.client is a dependency of get(), this is what you need to mock.
Edited in response to question changes
This is terrible: (status_code / 100).
Test for the real status code there.
You should do the following:
Create a mock OkHttpClient.
Inject the mock into your test class using reflection.
test the get method.
You may want to change the mocking of the ok thing in the code below,
but you should be able to just use simple Mockito mocks for everything.
Here is some example code:
public class TestOkHttp
{
private static final String VALUE_JSON_STRING "some JSON string for your test";
private OkHttp classToTest;
#Mock
private ClassWithExecute mockClassWithExecute;
#Mock
private OkHttpClient mockOkHttpClient;
#Mock
private Response mockResponse;
#Mock
private ResponseBodyClass mockResponseBodyClass;
#Mock
private Request mockRequest;
private Gson testGson;
#Test
public void get_describeTheTest_expectedResults()
{
final JSONUnmarshaler<someclass> unmarshallerForThisTest = new JSONUnmarshaler<>()
// setup the mocking functionality for this test.
doReturn(desiredStatusCode).when(mockResponse).code();
classToTest.get()
}
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new OkHttp();
testGson = new Gson();
doReturn(mockResponse).when(mockClassWithExecute).execute();
doReturn(mockClassWithExecute).when(mockOkHttpClient).newCall(mockRequest);
doReturn(mockResponseBodyClass).when(mockResponse).body();
doReturn(VALUE_JSON_STRING).when(mockResponseBodyClass).string();
ReflectionTestUtils.setField(classToTest,
"client",
mockOkHttpClient);
}
}
I am trying to write unit tests for repository while using MVVM pattern in android.
What i have is a repository which fetched data from the network using retrofit
public class ValidateCbuRepository {
private static ValidateCbuRepository single_instance = null;
private MutableLiveData<CBUValidationImageResponse> data = new MutableLiveData<>();
public static ValidateCbuRepository getInstance() {
if (single_instance == null)
single_instance = new ValidateCbuRepository();
return single_instance;
}
public MutableLiveData<CBUValidationImageResponse> processImage(String encodedString) {
JsonObject postParam = new JsonObject();
postParam.addProperty("image", encodedString);
Api service = RetrofitClientInstance.getRetrofitInstance().create(Api.class);
data.setValue(null);
HttpUrl httpUrl = HttpUrl.parse("some url");
Call<CBUValidationImageResponse> responseCall = service.getProcessedImage_cbu_validation(httpUrl.toString(),postParam);
responseCall.enqueue(new Callback<CBUValidationImageResponse>() {
#Override
public void onResponse(Call<CBUValidationImageResponse> call, Response<CBUValidationImageResponse> response) {
if(response.isSuccessful()) {
CBUValidationImageResponse res = response.body();
CBUValidationImageResponse cbuValidationImageResponse = res;
Log.i("CBU response ",""+cbuValidationImageResponse.toString());
cbuValidationImageResponse.setSuccess(true);
cbuValidationImageResponse.setShowProgres(false);
cbuValidationImageResponse.setError(false);
data.setValue(cbuValidationImageResponse);
}
}
#Override
public void onFailure(Call<CBUValidationImageResponse> call, Throwable t) {
CBUValidationImageResponse cbuValidationImageResponse = new CBUValidationImageResponse();
cbuValidationImageResponse.setError(true);
cbuValidationImageResponse.setShowProgres(false);
data.setValue(cbuValidationImageResponse);
t.printStackTrace();
}
});
return data;
}
}
The unit test part
#Mock
private Observer<CBUValidationImageResponse> observer;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testApiResponse_success() {
Api mockedApiInterface = Mockito.mock(Api.class);
Call<CBUValidationImageResponse> mockedCall = Mockito.mock(Call.class);
Mockito.when(mockedApiInterface.getProcessedImage_cbu_validation(any(),any())).thenReturn(mockedCall);
try {
Mockito.doAnswer(new Answer() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Callback<CBUValidationImageResponse> callback = invocation.getArgument(0);
CBUValidationImageResponse cbuValidationImageResponse = new CBUValidationImageResponse();
cbuValidationImageResponse.setCBU_code("some code");
cbuValidationImageResponse.setHeight(7);
cbuValidationImageResponse.setBreadth(7);
cbuValidationImageResponse.setLength(7);
callback.onResponse(mockedCall, Response.success(cbuValidationImageResponse));
// or callback.onResponse(mockedCall, Response.error(404. ...);
// or callback.onFailure(mockedCall, new IOException());
return null;
}
}).when(mockedCall).enqueue(any(Callback.class));
ValidateCbuRepository validateCbuRepository = new ValidateCbuRepository();
String encodedString= "";
validateCbuRepository.processImage(encodedString).observeForever(observer);
Getting a null pointer exception at validateCbuRepository.processImage(encodedString).observeForever(observer). Next step is to verify the observer.
I expect the test to pass. What am i doing wrong here?. I did something similar foe view model and the test passes with 100% code coverage.
The retrofit call is asynchronous. Is that the reason why it fails?
Edit : It seems livedata is null while testing causing NPE.
This is a part of my class, I want to test:
public class PrefPanel extends Composite {
private static PrefPanelUiBinder uiBinder = GWT.create(PrefPanelUiBinder.class);
interface PrefPanelUiBinder extends UiBinder<Widget, PrefPanel> {}
public PrefPanel(GlobalParams globalParams) {
initWidget(uiBinder.createAndBindUi(this));
String url = URL.encode(globalParams.getBaseUrl() + "book.html");
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url);
try {
Request response = builder.sendRequest(jsonString, new RequestCallback() {
#Override
public void onError(Request request, Throwable exception) {
displayError("Error");
}
#Override
public void onResponseReceived(Request request, Response response) {
updateBookList(response.getText());
}
});
} catch (RequestException e) {
displayError("Error");
}
Here is a part of my test class:
#RunWith(GwtMockitoTestRunner.class)
public class PositionServiceTest {
#Mock RequestBuilder builder;
#Mock GlobalParams globalParams;
#Mock URL url;
private PrefPanel prefPanel;
#Before
public void setup() {
GwtMockito.useProviderForType(RequestBuilder.class, new FakeProvider() {
#Override
public Object getFake(Class aclass) {
return builder;
}
});
when(globalParams.getBaseUrl()).thenReturn("http://localhost/");
prefPanel = new PrefPanel(globalParams);
...
When I start to debug I get an error message:
- url cannot be empty
- java.lang.IllegalArgumentException
- at com.google.gwt.http.client.StringValidator.throwlfEmptyOrNull(StringValidator.java:52)
- ...
The error occurs on the line where I create the RequestBuilder (new RequestBuilder). I have no idea how to create a new instance of RequestBuilder. Could you give me a clue?
I have heard that gwtmockit can't handle constructors. Is there a way to avoid the new RequestBuilder? Do I have to use powermockito?
I've read about how HttpClient's LocalTestServer can be used for automated testing, however I can't seem to find where it's been moved. I tried defining dependency to httpclient with tests classifier:
'org.apache.httpcomponents:httpclient:4.5.2:tests'
but there doesn't seem to be a LocalTestServer class defined in there. Has this been discontinued?
Your test should now extend org.apache.http.localserver.LocalServerTestBase.
This is available in the httpclient module with classifier tests.
Your pom could look like:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
Related issue:
https://issues.apache.org/jira/browse/HTTPCLIENT-1172
Related changeset:
https://github.com/apache/httpclient/commit/2ebd8202849c1f4a17d4320543e315a46cbfdc10
Can use simple implementation of the LocalServer
public class LocalHttpServer extends ExternalResource {
private static final Logger log = LoggerFactory.getLogger(LocalHttpServer.class);
private final int port;
private MockServer server;
public LocalHttpServer(int port) {
this.port = port;
}
#Override
protected void before() throws Throwable {
server = new MockServer();
server.setUp();
}
public void start() throws Exception {
server.start(port);
log.info("LocalHttpServer started on {}", port);
}
/**
* Need to be setup before starting server
*/
public LocalHttpServer registerSimpleHandler(String path, String resp) {
server.registerSimpleHandler(path, resp);
return this;
}
#Override
protected void after() {
try {
server.shutDown();
} catch (Exception e) {
e.printStackTrace();
}
log.info("LocalHttpServer shutdown on {}", port);
}
static class MockServer extends LocalServerTestBase {
#Override
public void setUp() throws Exception {
super.setUp();
HttpRequestFactory requestFactory = new DefaultHttpRequestFactory() {
#Override
public HttpRequest newHttpRequest(final RequestLine requestline) throws MethodNotSupportedException {
return super.newHttpRequest(requestline);
}
};
HttpMessageParserFactory<HttpRequest> requestParserFactory = new DefaultHttpRequestParserFactory(
BasicLineParser.INSTANCE, requestFactory);
DefaultBHttpServerConnectionFactory connectionFactory = new DefaultBHttpServerConnectionFactory(
ConnectionConfig.DEFAULT, requestParserFactory, DefaultHttpResponseWriterFactory.INSTANCE);
this.serverBootstrap.setConnectionFactory(connectionFactory);
}
public void registerSimpleHandler(String path, String resp) {
this.serverBootstrap.registerHandler(path, (request, response, context) ->
response.setEntity(new StringEntity(resp, ContentType.TEXT_PLAIN)));
}
public void start(int port) throws Exception {
this.serverBootstrap.setListenerPort(port);
start();
}
}
Example usage
public class HttpTest {
private static final LocalHttpServer LOCAL_HTTP = new LocalHttpServer(8080);
#ClassRule
public static final RuleChain RULE_CHAIN = RuleChain.outerRule(LOCAL_HTTP);
#Before
public void setUp() throws Exception {
LOCAL_HTTP.registerSimpleHandler("/path", "response")
.start();
}
#Test
public void someTest() {
//request here
}
}
I have a test that takes a lot of time and ended up making a timeout.
I tried the solution bob and nothing it does not work.
The error occurs just on tests PUT.
My Test :
#Test
public void testUpdateUse(){
setExpectedResponse("{\"id\":1,\"username\":\"test\",\"email\":\"bob#test.ca\"}");
User userToUpdate = new User();
userToUpdate.setEmail("bob#test.ca");
userToUpdate.setUsername("superbob");
userToUpdate.setId(1);
UserOrganization userOrganization = new UserOrganization();
userOrganization.setOrganizationId(1);
List<UserOrganization> userOrganizations = new ArrayList<>();
userOrganizations.add(userOrganization);
UserOrganizationUnit userOrganizationUnit = new UserOrganizationUnit();
userOrganizationUnit.setOrganizationUnitId(1);
List<UserOrganizationUnit> userOrganizationUnits = new ArrayList<>();
userOrganizationUnits.add(userOrganizationUnit);
userToUpdate.setOrganizations(userOrganizations);
userToUpdate.setOrganizationUnits(userOrganizationUnits);
userAPIService.update(1, userToUpdate);
assertLatestRequest("PUT", "/users/1");
}
#Before
public void setUpServer() throws Exception {
Thread.sleep(500);
expectedResponse = null;
final Authenticator authenticator = new BasicAuthenticator("") {
#Override
public boolean checkCredentials(final String username, final String password) {
return getUsername().equals(username) && getPassword().equals(password);
}
};
final HttpHandler handler = new HttpHandler() {
#Override
public void handle(HttpExchange exchange) throws IOException {
final Authenticator.Result authResult = authenticator.authenticate(exchange);
if (authResult instanceof Authenticator.Success || !basicAuthRequired) {
latestExchange = exchange;
StringWriter writer = new StringWriter();
try {
IOUtils.copy(new InputStreamReader(latestExchange.getRequestBody()), writer, 1024);
} catch (IOException e) {
e.printStackTrace();
}
latestRequestBody = writer.toString();
byte[] response = expectedResponse.getBytes();
exchange.getResponseHeaders().add("Content-type", expectedContentType);
exchange.sendResponseHeaders(expectedStatus, response.length);
exchange.getResponseBody().write(response);
}
exchange.close();
expectedResponse = null;
}
};
httpServer = HttpServer.create(new InetSocketAddress(testPort), 0);
httpServer.createContext("/", handler);
httpServer.start();
}
#After
public void tearDownServer() throws Exception {
if (httpServer != null) {
httpServer.stop(0);
}
context.assertIsSatisfied();
Thread.sleep(500);
}
example code on applicationContext.xml:
<http:conduit name="{http://service.clientapi.user.com/}*.http-conduit">
<http:client CacheControl="no-store" Connection="Keep-Alive" AllowChunking="false" ConnectionTimeout="10000" ReceiveTimeout="60000"/>
</http:conduit>
Version CXF : 2.7.3
Version Spring 3
Java 7
My solution was to override the httpconduit in my test context.xml
<http:conduit name="*.http-conduit">
<http:client CacheControl="no-store" Connection="Keep-Alive" AllowChunking="false" ConnectionTimeout="10000" ReceiveTimeout="60000"/>
</http:conduit>