I have the following Java method:
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = new ESBUrlHelper().getEsbUrl();
AppointmentClient appointmentClient = AppointmentClientFactory.getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
The method above makes a call to a third party REST client called appointmentClient.
The issue that I am having is that this is causing my test to fail.
How can I mock the appointmentClientobject within my unit tests?
Currently my test looks as follows:
#Test
public void shouldAddAppointment() {
// act
Appointment appointment = appointmentService.addAppointment(CLIENT_STRING, appointmentMock)
// assert
assertNotNull(appointment);
}
But I get the following error at line appointmentClient.addAppointment(client, appointment);:
org.jboss.resteasy.client.exception.ResteasyIOException: IOException
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
I want to mock something like as follows:
Mockito.when(appointmentClient.addAppointment(client, appointment)).thenReturn(appointmentMock);
You can try using PowerMockito for this.
First, you need to mock the static method call of AppointmentClientFactory class like below:
PowerMockito.mockStatic(AppointmentClientFactory.class);
PowerMockito.when(AppointmentClientFactory,"getUnsecuredClient",esbUrl).thenReturn(appointmentClient);
And also, when you use PowerMockito for mocking static methods, add the #PrepareForTest({AppointmentClientFactory.class}) annotation to the test class.
With your current code, the only way of mocking a call to AppointmentClientFactory#getUnsecuredClient would be using PowerMock, since the factory method is static. This is due to the hard coupling between your calling code addAppointment and the dependency here (i.e. the AppointmentClientFactory).
If I were you, I would avoid that as PowerMock is not the best way to do tests. Instead, what I would do, would be to inject the AppointmentClientFactory as a dependency thus allowing me to mock an instance of it during my tests.
This should be the best approach in twofold manner. Firstly, because you achieve less tightly coupled code and secondly because you do not need to use PowerMock for your unit-tests.
It's not impossible with Mockito. But your original problem is static method of AppointmentClientFactory. You definitely should change this method to the instance method (at least for better architecture) , for example:
public class AppointmentClientFactory {
public AppointmentClient getUnsecuredClient(String url) {
return new AppointmentClient(); //your implementation
}
}
Then your AppointmentService will look like (or close to it):
public class AppointmentService {
private final AppointmentClientFactory factory;
public AppointmentService() {
this(new AppointmentClientFactory());
}
public AppointmentService(AppointmentClientFactory factory) {
this.factory = factory;
}
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = "";
Appointment outputAppointment = null;
AppointmentClient appointmentClient = new AppointmentClientFactory().getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
}
And then you will could write test like:
public class AppointmentTest {
private final String CLIENT_STRING = "";
#Test
public void shouldAddAppointment() {
AppointmentClientFactory clientFactory = Mockito.mock(AppointmentClientFactory.class);
AppointmentClient mockedClient = Mockito.mock(AppointmentClient.class);
AppointmentService service = new AppointmentService(clientFactory);
Appointment appointmentMock = new Appointment();
when(clientFactory.getUnsecuredClient(any())).thenReturn(mockedClient);
Appointment appointment = service.addAppointment(CLIENT_STRING, appointmentMock);
assertNotNull(appointment);
}
}
Related
I am currently working on a AWS Lambda using Java 11. It is requiring me for an implementation of the handler to have an empty constructor. My handler looks like this
public class ApiKeyHandler {
private final SecretsManagerClient secretsManagerClient;
public ApiKeyHandler() {
secretsManagerClient = DependencyFactory.secretsManagerClient();
}
public void handleRequest(Object event, Context context) {
//Other codes here
secretsManagerClient.getSecret(/../);
}
}
And Dependency Factory class
public class DependencyFactory {
private DependencyFactory() {}
/**
* #return an instance of SecretsManagerClient
*/
public static SecretsManagerClient secretsManagerClient() {
return SecretsManagerClient.builder()
.region(/**/)
.build();
}
}
Now, when I am trying to write unit test for this I cant mock objects in constructor. Is there a way I can mock it?
I tried
#Mock SecretsManagerClient secretsManagerClient;
#InjectMocks ApiKeyHandler handler;
but no luck. Thank you
It looks like you have a couple of options:
You can add another constructor with the parameters to inject. This is easy and clean from the test perspective, but after all you'll have the code in production (this constructor in this case) that is used only for tests.
In generally I don't advocate this approach, although I understand that there are technology limitations here.
You can Mock the Dependency Factory. Since the call is static, you might end up using PowerMock / PowerMockito that can actually mock static calls. This is something that can turn to be really painful to maintain, in general this approach is discouraged these days.
You can Rewrite the DependencyFactory so that it could be configured with some kind of mock implementation (that will allow to specify mock dependencies):
public interface DependencyFactoryMode {
SecretsManagerClient secretsManagerClient();
}
public class RealDependencyFactoryMode implements DependencyFactoryMode {
public SecretsManagerClient secretsManagerClient() {
return SecretsManagerClient.builder()
.region(/**/)
.build();
}
}
// in src/test/java - test code in short
public class DependencyFactoryTestMode implements DependencyFactoryMode {
private SecretsManagerClient smc = Mockito.mock(SecretsManagerClient.class);
public SecretsManagerClient secretsManagerClient() {
return smc;
}
// this will be used in tests
public SecretsManagerClient getSmcMock() {return smc;}
}
public class DependencyFactory {
private static DependencyFactoryMode mode;
static {
// depending on the configuration, external properties or whatever
// initialize in production mode or test mode
// of course this is the most "primitive" implementation you can probably
// do better
if(isTest) {
mode = new TestDependencyFactoryTestMode();
} else {
// this is a default behavior
mode = new RealDependencyFactoryMode();
}
}
private DependencyFactory() {}
public static DependencyFactoryMode getMode() {
return mode;
}
public static SecretsManagerClient secretsManagerClient() {
return mode.secretsManagerClient();
}
}
With this approach you'll have to pre-configure the dependency factory so that while running in the test it will "know" that it should run in the test mode.
public class Test {
#Test
public void test() {
// DependencyFactoryMode will be used in the test mode
DependecyFactoryMode testMode = DependencyFactory.getMode();
var smc = testMode.secretsManagerClient();
Mockito.when(smc.foo()).thenReturn(...);
}
}
Now this approach suffers from the same drawback as "1" but at least you have a code "only for tests" only in the factory, rather than in all lambda functions (I assume you have many of them, otherwise probably the first approach will be the least of all evils).
Another possible drawback is that the same instance of DependencyFactory (with the shared static mocking mode) will be shared between the tests, so you might end up "reseting" all the relevant mocks after the test.
Again, these all are complications because in the form that you've presented there is no way to provide a dependency injection in constructor because of the technology limitation.
Add a second constructor that accepts parameters:
public ApiKeyHandler(SecretsManagerClient client) {
secretsManagerClient = client;
}
public ApiKeyHandler() {
this(DependencyFactory.secretsManagerClient());
}
I have a code that I cannot correctly cover with tests.
I am using the Mockito library.
And I had difficulty at the moment of starting the test.
Below is the test code:
#Test
public void testLoadCar() {
when(remoteService.loadData()).thenReturn(new DataResult<DataCar>("", "", new DataCar()));
when(dataResult.hasError()).thenReturn(true);
when(dataResult.response.hasHeaders()).thenReturn(true);
requestNetwork = new RequestNetwork(remoteService);
Response<DataCar> response = requestNetwork.load(request);
}
These are objects in the test class: remoteService, dataResult, request.
I am concerned about the moment where I am trying to implement the when method:
when(dataResult.response.hasHeaders()).thenReturn(true);
I would like to know if such a recording will work.
If it doesn't work, then how can we handle this moment:
protected Response createResponse(DataResult<T> dataResult) {
if (dataResult.hasError() || !dataResult.response.hasHeaders()) {
return dataResult.getErrorMessage());
} else {
return Response.data(dataResult.value);
}
}
This is a method on the system under test (SUT) that has a createResponse() method. This method contains a call to the mock method of the DataResult object.
To implement dataResult.hasError () I got it:
when (dataResult.hasError ()). thenReturn (true);
Then with! DataResult.response.hasHeaders () I have a problem. Since I don't understand how to substitute the value I need.
Not all objects that your object under test interacts with need to be mocks.
Remember that you can use POJOs as well.
DataResult looks like a perfect candidate for a POJO.
You gain nothing by using a mock objet if you can create a POJO with desired state and behaviour.
Looking at the posted code, it looks like it is easy to create:
new DataResult<DataCar>("", "", new DataCar())
On top of that:
Your code looks suspicious to me.
when stubbing remoteService.loadData() you create a new instance of DataResult
subsequently, you stub some calls on dataResult, which is not an object returned from remoteService.loadData()
And to answer original post:
You can set fields on mocks (directly if access modifiers allow it, or via reflection otherwise). Note that this is highly not-idiomatic and surprising use of mocks.
class A {
B b;
}
class B {
boolean hasHeaders() {
return true;
}
}
#ExtendWith(MockitoExtension.class)
public class AAATest {
#Mock
A aMock;
#Mock
B bMock;
#BeforeEach
void setupMocks() {
aMock.b = bMock;
}
#Test
void testFieldInMockIsInitialized() {
Assertions.assertEquals(bMock, aMock.b);
}
}
When I used Powermock to mock a private method, and then verify it in another method's unit test, to check if it was called and with correct times. But I found I can verify whether the method was called and with the correct param, the called times of the method can be any number, however the unit test always passed. If someone can help me solve the problem. thx!
This is my source code:
public enum ConversionCommon{
INSTANCE;
...
public void getConvertTypeData(JSONObject result, JSONObject conversionData, String intent){
String uncertainty = "";
String unit1 = "";
String unit1_char = "";
if(result.has(ConversionDefine.CONVERSION_UNCERTAINTY)){
uncertainty = result.getString(ConversionDefine.CONVERSION_UNCERTAINTY);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1)){
unit1 = result.getString(ConversionDefine.CONVERSION_UNIT1);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1_CHAR)){
unit1_char = result.getString(ConversionDefine.CONVERSION_UNIT1_CHAR);
}
setUnitCount(conversionData, uncertainty, intent);
setDestUnits(conversionData, unit1, unit1_char);
}
}
The method getConvertTypeData() calls two methods once. The follow is my test case code:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ConversionCommon.class, LengthConversion.class })
#PowerMockIgnore("javax.management.*")
public class ConversionCommonTest{
#Before
public void setUp() throws Exception{
PowerMockito.mockStatic(LengthConversion.class);//
PowerMockito.spy(LengthConversion.class); //
}
#Test
public void should_getConvertTypeData_invoke_setUnitCount() throws Exception{
JSONObject result = new JSONObject();
JSONObject conversionData = new JSONObject();
result.put(ConversionDefine.CONVERSION_UNCERTAINTY, "3");
result.put(ConversionDefine.CONVERSION_UNIT1, "meter");
result.put(ConversionDefine.CONVERSION_UNIT1_CHAR, "centmeter");
suppress(method(ConversionCommon.class, "setUnitCount", JSONObject.class, String.class, String.class));
ConversionCommon.INSTANCE.getConvertTypeData(result, conversionData, ConversionDefine.INTENT_LENGTH_CONVERSION);
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(1)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
}
The test case can run successful but if I change the last line to ...
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(100)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
... and re-run the test case. The result is also passed. But in fact I only call the method setUnitCount only once in Refo.
The edition of test framework: mockito:1.10.19;powermock:1.6.5
How can I correct verify the private method's call times with the API PowerMockito.verifyPrivate();
You are doing right, except one thing. You're spying on enum constant. And each enums constant is separate inner class. So you have to add two things:
Enum constant to #PrepareForTest with using fullyQualifiedNames, like `#PrepareForTest(values = { ConversionCommon.class, LengthConversion.class }, fullyQualifiedNames = "com.somepackage.ConversionCommon$INSTANCE")
Create a spy for instance: PowerMockito.spy(ConversionCommon.INSTANCE)
Replace constant with spy: Whitebox.setInternalState(ConversionCommon.class, spy)
Now, you can stub the spy method as usual doNothing().when(spy, "setUnitCount");
Code snippet for some abstract singleton implement via enum:
enum
public enum Singleton {
INSTANCE;
public void doSomething(){
callPrivateMethod();
}
private void callPrivateMethod() {
}
}
test
RunWith(PowerMockRunner.class)
#PrepareForTest(value = Singleton.class, fullyQualifiedNames = "com.stackoverflow.q46212600.Singleton$INSTANCE")
public class ClassUseSingletonTest {
#Test
public void should_verify_enum_method() throws Exception {
final Singleton spy = PowerMockito.spy(Singleton.INSTANCE);
Whitebox.setInternalState(Singleton.class, spy);
doNothing().when(spy, "callPrivateMethod");
new ClassUseSingletone().doSomething("do");
PowerMockito.verifyPrivate(Singleton.INSTANCE, times(1)).invoke("callPrivateMethod");
}
}
Full example, you may find here
I am new to writing tests in java, and seem to be unable to test if a method of a class is called.
I am sending metrics to datadog, and want to test in the code if a function of another class was called.
It says I need to mock first, but I couldn't get it to work.
MetricRecorder.java
import com.timgroup.statsd.StatsDClient;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.google.common.base.Preconditions;
public class MetricRecorder {
private final String namespace;
private final static StatsDClient metrics = new NonBlockingStatsDClient(
"my.prefix",
"localhost",
8125,
new String[] {"tag:value"}
);
public MetricRecorder(String namespace) {
Preconditions.checkNotNull(namespace);
this.namespace = namespace;
}
public void inc(String metricName) {
this.inc(metricName, 1);
}
public void inc(final String metricName, final long value) {
Preconditions.checkNotNull(metricName);
try {
metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value);
} catch (Exception e) {
logger.warn("Unable to record metric {} due to :", metricName, e);
}
}
...
}
MetricRecorderTest.java
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
MetricRecorder recorder = new MetricRecorder("dev");
recorder.inc("foo", 1);
verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1);
}
}
When I run the test I get this => org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type NonBlockingStatsDClient and is not a mock!
Any idea of how I should be testing if recordHistogramValue was called, and if so with what arguments?
Since it looks like StatsDClient is an interface of some kind, it would make your testing effort easier to simply inject this dependency into your object. Even if you're not using an IoC container like Spring or Guice, you can still somewhat control this simply by passing an instance of it in through the constructor.
public MetricRecorder(String namespace, StatsDClient client) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(client);
this.namespace = namespace;
this.client = client;
}
This will make your testing simpler since all you realistically need to do is mock the object passed in during test.
Right now, the reason it's failing is because you're newing up the instance, and Mockito (in this current configuration) isn't equipped to mock the newed instance. In all honesty, this set up will make testing simpler to conduct, and you should only need your client configured in one area.
#RunWith(MockitoJUnitRunner.class)
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
StatsDClient dClientMock = Mockito.mock(StatsDClient.class);
MetricRecorder recorder = new MetricRecorder("dev", dClientMock);
recorder.inc("foo", 1);
verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1);
}
}
You are getting things wrong here. You don't use a mocking framework to test your "class under test".
You use the mocking framework to create mocked objects; which you then pass to your "class under test" within a test case. Then your "code under test" calls methods on the mocked object; and by controlling returned values (or by verifying what happens to your mock); that is how you write your testcases.
So, your testcase for a MetricRecorder doesn't mock a MetricRecorder; it should mock the StatsDClient class; and as Makoto suggests; use dependency injection to put an object of that class into MetricRecorder.
Besides: basically writing "test-able" code is something that needs to be practiced. I wholeheartedly recommend you to watch these videos if you are serious about getting in this business. All of them; really (worth each second!).
I'm current using mockito 1.8.4 in this spring mvc application. Here is the code for the class/method I am trying to test.
public class CompleteTaskController implements IController {
public static Logger log = Logger.getLogger(CompleteTaskController.class);
#Override
public void handle() {
GUIFactory gf = new GUIFactory();
IDatabasePullListOfUsers pull = new OraclePullListOfUsers();
IDatabaseUserManagement manage = OracleUserManagement.getInstance();
gf.makeGUI("completeTask", pull.pullAssignedRequests(GUIFactory.userLoggedIn));
manage.completeTask(gf.getRequestID(), GUIFactory.userLoggedIn);
gf.makeCustomGUI("Task has been completed");
log.fatal(GUIFactory.userLoggedIn + " has completed the task of request id " + gf.getRequestID());
gf.makeGUI("adminpanel");
}
}
so far, all the tests pass BUT the last one - which I just can't seem to understand why. Here is the code for my tests:
public class CompleteTaskControllerTest {
#Test
public void testHandleCallsMakeGUIAndPassesItPullAssignedRequestsAndAString(){
CompleteTaskController mockCtc = mock(CompleteTaskController.class);
GUIFactory mockGf = mock(GUIFactory.class);
IDatabasePullListOfUsers mockPull = mock(OraclePullListOfUsers.class);
mockCtc.handle();
verify(mockGf).makeGUI("test", mockPull.pullAssignedRequests("test"));
}
#Test
public void testHandleCallsCompleteTaskAndPassesItGetRequestIDAndAString(){
CompleteTaskController mockCtc = mock(CompleteTaskController.class);
IDatabaseUserManagement mockManage = mock(OracleUserManagement.class);
GUIFactory mockGf = mock(GUIFactory.class);
mockCtc.handle();
when(mockGf.getRequestID()).thenReturn(1);
verify(mockManage).completeTask(mockGf.getRequestID(),"Test");
}
#Test
public void testHandleCallsMakeCustomGUIAndPassesItAString(){
CompleteTaskController mockCtc = mock(CompleteTaskController.class);
GUIFactory mockGf = mock(GUIFactory.class);
mockCtc.handle();
verify(mockGf).makeCustomGUI("test");
}
}
Sorry for throwing all this code at you - the only test I am having issues with is the third test - which is trying to mock the gf.makeCustomGUI("Task has been completed") method!
With the statement
verify(mockGf).makeCustomGUI("test");
are you trying to verify whether the "makeCustomerGUI" has been called with argument "test". And if that is your requirement, you can do that as below:
GUIFactory mockGf = mock(GUIFactory.class);
mockGf.makeCustomerGUI("test");
verify(mockGf).makeCustomGUI("test");
Once your mock object is created, Mockito will remember all invocations on it. So you can selectively verify the invocations.