I'm running a JUnit test - testing an action that chains.
We have a large internal testing framework (inherits from StrutsTestCase) that sets up everything for an action to work during a test but when chaining to a new action - the new (chained) action isn't setup correct and internal code runs into NULLs.
I believe the test should only test for the correct result from the action call and should not test the chained action.
My Q: I'm looking for a way to disable chaining while testing. Can the Dispatcher created in StrutsTestCase.setUp() be configured to handle chaining differently (eg. do nothing)?
Wish I could avoid chaining but that's the way it's done here.
EDIT - Here is code:
Action:
#Action(value = SUBMIT, results = {
#Result(name = SUCCESS, type = "chain", params = { "actionName", "myActionName", "namespace", "/myNameSpace" }) })
public String submitForm() throws IllegalAccessException, InvocationTargetException, IOException {
return SUCCESS;
}
Test:
#Test
public void testStuff() throws Exception {
setupAction();
prepareForValidUser();
this.actionUnderTest.getModel().setUpSomeStuff(someSetupValue);
final String result = this.proxy.execute();
assertEquals("Result not the expected result", SUCCESS, result);
}
The test relies heavily on a nice testing framework; proxy.execute() is what runs the action (com.opensymphony.xwork2.ActionProxy.class).
The solution is to simply call the action method directly instead of relying on the struts framework to execute the action for you.
This:
final String result = this.proxy.execute();
becomes
final String result = this.actionUnderTest.myActionMethod();
This worked well for me! Doing this meant that nothing handled/executed on the result of the action method (eg. no chaining occurred).
Related
I have a function I need to test:
#Override
public ResponseEntity<BasicResponse> myFunction(HttpServletRequest request, #RequestBody Dto dto, BindingResult result) {
try {
ValidationUtils.invokeValidator(validator, dto, result);
if (result.hasErrors()) {
// do things
} else {
//do things
}
} catch (Exception e) {
// catch
}
//return things;
}
But when I test the function it always go to the catch because of the validator, it says:
"Validator does not support Dto".
I don't care about the validation, I need to test what's inside the try, so I try to use doNothing to skip the validation but I get an error because it's void:
#Test
void TestMyFunction() {
doNothing().when(ValidationUtils.invokeValidator(validator, dto, result));
ResponseEntity<BasicResponse> response = controller.myFunction(request, dto, result);
// assert something
}
Any idea on how to proceed? I can't change the function, I can only write the test and I'm new at this. Thank you.
If ValidationUtils was an object instance that is a Mockito spy or mock, you would be able to mock it like so:
doNothing()
.when(validationUtils)
.invokeValidator(validator, dto, result);
This, unfortunately, does not seem to be the case in your test - ValidationUtils seems to be a class on which a static method is called, which Mockito can handle since version 3.4.0 (before that it was usually handled by PowerMock). thenAnswer should be used with the mockedStatic object instance, similarly to this answer, since the method's return type is void.
An important additional (but mandatory) note: mocking static methods is discouraged and should be avoided whenever possible. It slows down the tests and is a sign of bad design of the classes. The validator should be injected into the class or created using a factory, thanks to that a mocked object instance could be easily used.
I've checked that and in fact the thenAnswer part is not required to do nothing after using mockStatic on a class.
try (var mockedStatic = Mockito.mockStatic(ValidationUtils.class)) {
// test code
}
The code above makes ValidationUtils do nothing and return default values (0, false, null).
See this example (all tests pass).
I recently developed few Verticles from which I needed to make external API calls. To optimize the code, I moved code of calling APIs to one common Helper class. I am also passing Vertx instance from Verticle to Helper class. I am now trying to write Junit test case for the Helper class which is looking like below working code.
public class ServiceExecutionHelper{
public Promise<String> executeService(String requestURI, JsonObject input, MultiMap headers, Vertx vertx){
Promise<String> promise = Promise.promise();
WebClient client = WebClient.create(vertx);
client.postAbs(requestURI).timeout(60000).putHeaders(headers)
.sendJsonObject(input, ar -> {
if (ar.succeeded()) {
HttpResponse<Buffer> response = ar.result();
JsonObject serviceRespone = new JsonObject(response.bodyAsString());
JsonArray responseData = serviceRespone.getJsonArray("response_data");
if(responseData != null){
promise.complete("promise_completed");
}else{
promise.fail("promise_failed");
}
}
}
return promise;
}
}
Can anyone please guide how could I write test case for above code?
There are a million ways to do this depending on what exactly you need to test.
Here is one suggestion using junit5 and okhttp's MockWebServer. There are a lot of other conceivable alternatives.
The test verifies:
That you send a POST request using the payload contained in the input parameter.
That your implementation can handle a json response from the webserver.
That your implementation sends exactly one request to the webserver.
That your code completes the Promise if the server's response contains the key "promise_completed"
#ExtendWith(VertxExtension.class)
#Slf4j
public class ServiceExecutionHelperTest {
private ServiceExecutionHelper sut;
private MockWebServer mockWebServer;
#BeforeEach
public void setUp() {
sut = new ServiceExecutionHelper();
mockWebServer = new MockWebServer();
}
#Test
public void testExecuteService(final Vertx vertx, final VertxTestContext testContext) throws InterruptedException {
// given
final JsonObject requestPayload = new JsonObject().put("request", new JsonArray("[]"));
final JsonObject serverResponsePayload = new JsonObject().put("response_data", new JsonArray("[]"));
mockWebServer.enqueue(new MockResponse()
.setBody(serverResponsePayload.encode())
.setResponseCode(200)
.setHeader("content-type", "application/json"));
// when
final Promise<String> stringPromise =
sut.executeService(
mockWebServer.url("/").toString(),
requestPayload,
MultiMap.caseInsensitiveMultiMap(),
vertx);
// then
final RecordedRequest recordedRequest = mockWebServer.takeRequest();
assertEquals("POST", recordedRequest.getMethod());
assertEquals("[text={\"request\":[]}]", recordedRequest.getBody().toString());
assertEquals(1, mockWebServer.getRequestCount());
testContext.assertComplete(stringPromise.future())
.map(val -> {
assertEquals("promise_completed", val);
testContext.completeNow();
return val;
})
.onComplete(onComplete -> {
assertTrue(onComplete.succeeded());
log.info("done");
})
.onFailure(onError -> Assertions.fail());
}
}
Some words from a TDD point of view
Before you start writing tests (and your actual code too, if you ask me), you should clarify your functional and technical requirements.
These should be the basis for your tests. And the tests should be a starting point to implement your code against.
So I cannot promise you that this example is a correct test for your use case. It compiles and and runs. But it should be verified and extended following your actual requirements.
Concerning test coverage
To keep this answer short and concise, I did not write the test to cover all possible branches. The case where the server responds without response_data (i.e. the else branch of your if-clause, where the Promise fails) is not tested.
To cover that case, a second test or the usage of a parameterized test would be necessary.
I have the next JUnit test, and it works fine, but finally in the verify it throws expectation failure. I think it is because the mocked PsPort is different of the PsPort that I send to the DataReader.
Is there any other way to test it?
#Test
public void testguardarMensaje() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, InstantiationException{
String datoTest = "1=123456";
Constructor<PsPort> constructor = PsPort.class.getDeclaredConstructor(new Class[] {String.class});
constructor.setAccessible(true);
PsPort port = constructor.newInstance("middleware.conf");
PsPort drMock;
int hash1 = datoTest.hashCode();
String hashString1 = String.valueOf(hash1);
String combinedIdDataHashString1 = datoTest +"="+ hashString1;
drMock = strictMock(PsPort.class);
byte[] datoByte = port.encriptarDesencriptarMensaje(combinedIdDataHashString1.getBytes(), Cipher.ENCRYPT_MODE);
drMock.guardarDato(datoByte);
replayAll();
int hash = datoTest.hashCode();
String hashString = String.valueOf(hash);
String combinedIdDataHashString = datoTest +"="+ hashString;
byte[] datoByte2 = port.encriptarDesencriptarMensaje(combinedIdDataHashString.getBytes(), Cipher.ENCRYPT_MODE);
DatagramPacket paquete = new DatagramPacket(datoByte2,datoByte2.length);
paquete.getData();
DataReader dr = new DataReader(port, null, 100, "=", "C:/Users/Asier/Desktop/logs/");
dr.guardarMensaje(paquete, port);
verifyAll();
}
It is really confusing that you have two port objects. What is the sense of creating a mocked drPort; when you are then giving a "real" port object to your class under test?
You see: you either create a mock and pass that down to your code under test (and then you have to setup the mock for the expected behavior; which you can afterwards verify); or you only provide "real" objects to your code under test, but then you would normally do some kind of asserts on the results of calls to "code under test".
So, in that sense, it doesn't really matter that there is at least one problem in your code:
drMock.guardarDato(datoByte);
replayAll();
There should be a call to EasyMock.expectLastCall() after the method invocation on drMock; but as said: as the mocked object isn't really used, that doesn't matter, on the one hand. Because, if you added that statement, your test would always fail; since your un-used mock would never see the calls that you specified it to see.
In order to give you some guidance; this is how you do such kind of testing in general:
SomeClassYouNeed mockedThingy = createStrict/Nice(SomeClassYouNeed.class);
expect(mockedThingy.foo()).andReturn("whatever");
mockedThingy.bar();
expectLastCall();
replay (mockedThingy);
ClassUnderTest underTest = new ClassUnderTest(mockedThingy);
underTest.doSomething();
verify(mockedThingy)
Meaning: any "object" that
a) your "class under test" needs to do its work
b) you want/have to "control" in a certain way
needs to be mocked; including a "specification" of all expected method calls.
Then you provide the mocked things to your code under test; execute the method you want to test ... to finally verify that the mock saw the behavior that you specified for it.
I am trying to use PowerMockito to mock the creation of the java.net.URL class in my code that I'm testing. Basically, I want to prevent the real HTTP request from occurring and instead 1) check the data when the request is made and 2) supply my own test data back on a mocked response. This is what I'm trying:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ URL.class, MockedHttpConnection.class })
public class Test {
URL mockedURL = PowerMockito.mock(URL.class);
MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class);
...
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL);
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
...
}
The code that I want to test looks like this:
URL wlInvokeUrl = new URL(wlInvokeUrlString);
connection = (HttpURLConnection) wlInvokeUrl.openConnection();
Earlier in my test scenario I mock the wlInvokeUrlString to match "MyURLString". I've also tried using various other forms of the whenNew line, trying to inject the mock. No matter what I try, it never intercepts the constructor. All I want to do is "catch" the call to openConnection() and have it return my mocked HTTP connection instead of the real one.
I have mocked other classes ahead of this one in the same script and these are working as expected. Either I need a second pair of eyes (probably true) or there is something unique about the URL class. I did notice that if I use "whenNew(URL.class).withAnyArguments()" and change the "thenReturn" to "thenAnswer" I could get it to trigger. Only problem is I never get the URL call for my code. What I see is an invocation of the 3-argument constructor for URL.class with all nulls for the parameters. Could it be this class is from the Java runtime and is bootstrapped by the test runner? Any help is much appreciated.
It's a common mistake when use PowerMockito.whenNew.
Note that you must prepare the class creating the new instance of MyClass for test, not the MyClass itself. E.g. if the class doing new MyClass() is called X then you'd have to do #PrepareForTest(X.class) in order for whenNew to work
From Powermock wiki
So, you need a bit change your test and add to #PrepareForTesta class which create a new instance of URLlike:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ URL.class, MockedHttpConnection.class , ConnectionUser.class})
public class URLTest {
public class URLTest {
private ConnectionUser connectionUser;
#Before
public void setUp() throws Exception {
connectionUser = new ConnectionUser();
}
#Test
public void testName() throws Exception {
URL mockedURL = PowerMockito.mock(URL.class);
MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class);
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL);
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
connectionUser.open();
assertEquals(mockedConnection, connectionUser.getConnection());
}
}
where:
public class ConnectionUser {
private String wlInvokeUrlString = "MyURLString";
private HttpURLConnection connection;
public void open() throws IOException {
URL wlInvokeUrl = new URL(wlInvokeUrlString);
connection = (HttpURLConnection) wlInvokeUrl.openConnection();
}
public HttpURLConnection getConnection() {
return connection;
}
}
I'm not sure the difference between .withParameterTypes(x) and .withArguments(x) but I believe you need to set it up as follows for your code to work. Give it a try and let me know if this doesn't help.
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(mockedURL);
The problem is that the arguments of the real call are not matching with the expected in your mock.
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL) will return mockedURL only the call is new URL("MyURLString").
If you change it to:
PowerMockito.whenNew( URL.class ).withParameterTypes( String.class )
.withArguments( org.mockito.Matchers.any( String.class ) ).thenReturn( mockedURL );
It will catch any string passed to the constructor URL(String) (even null) and return your mock.
When you tried
"whenNew(URL.class).withAnyArguments()" and change the "thenReturn" to
"thenAnswer" I could get it to trigger. Only problem is I never get
the URL call for my code. What I see is an invocation of the
3-argument constructor for URL.class with all nulls for the
parameters.
PowerMock will try to mock all constructors (org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing.InvokeStubMethod at line 122) then it calls the first one (with 3 arguments) and mock its answer. But the subsequent calls will return the already mocked one because you told it to mock for any arguments. That's why you see just one call with null, null, null in your Answer.
Using JUnit 4 API, is there a way to get a handle to a method in a test class that are annotated with #Test?
Here's what I am currently doing:
JUnitCore core = new JUnitCore();
Request request = Request.aClass(MyTest.class);
Result result = core.run(request);
if(result.wasSuccessful())
System.out.println("SUCCESS"); // or do something else
This code will run all tests in MyTest. However, what I want is to just specify the test class name at the beginning (MyTest.class) and do following in a loop:
Get next #Test annotated test in the class.
Print details
Run the test (possibly using Request.method(MyTest.class, "myTestMethod")
I can perhaps use reflection to get the method names and check if they are annotated with Test, but wanted to see if the JUnit API already provides this functionality.
You can use TestClass:
public void runTests(Class<?> clazz) {
TestClass testClass = new TestClass(MyTest.class);
List<FrameworkMethod> tests = testClass.getAnnotatedMethods(
Test.class);
for (FrameworkMethod m : tests) {
String methodName = m.getName();
Request request = Request.method(clazz, methodName);
JUnitCore core = new JUnitCore();
Result result = core.run(request);
if (result.wasSuccessful())
System.out.println(m + ": SUCCESS");
}
}
}
Note that this is an inefficient way to run tests, especially if you have class rules or you use #BeforeClass or #AfterClass