How to programmatically execute a test suite using JUnit4? - junit

I am trying to invoke a JUnit Test suite using the API. I know that you can suite up test classes using the following:
#RunWith(Suite.class)
#Suite.SuiteClasses({
Test1.class,
Test2.class, ...
})
But, is there a way to trigger the entire suite using the Java API, using JUnitCore for example?
For example, you can trigger a test by using the following code:
Runner r =
try {
r = new BlockJUnit4ClassRunner(Class.forName(testClass));
} catch (ClassNotFoundException | InitializationError e) {
// handle
}
JUnitCore c = new JUnitCore();
c.run(Request.runner(r));
Update:
From the API, it seems that the Suite class itself is a runner, hence the following code seems to work:
Suite suite = new Suite(klass, new RunnerBuilder() {
... // Implement methods
});
JUnitCore c = new JUnitCore();
c.run(Request.runner(suite));
But I am not sure if this is a recommended approach or if there is any downside to writing the above code.

Just specify the name of the suite class to JUnitCore:
Computer computer = new Computer();
JUnitCore jUnitCore = new JUnitCore();
jUnitCore.run(computer, MySuite.class);

You can also that using command prompt as
java org.junit.runner.JUnitCore test class name

Related

Is it fine to use block() in spring reactor tests for test state creation?

I'm writing integration tests using Spring, JUnit 5, JOOQ, TestContainers and Project Reactor. I want to test my repository layer, e.g. verify
Mono<Entity> get(Long id) method.
Therefore, my test should first create entity in database and then verify, that this entity exists. There are two approaches how to do it
Do everything in non-blocking way, e.g.
#Test
public void testGetById() {
var entityPojo = new EntityPojo().setName(UUID.randomUUID());
entityRepository.create(entityPojo)
.zipWhen(e -> entityRepository.get(e.getId()))
.as(StepVerifier::create)
.assertNext(t -> assertThat(t.getT1()).isEqualTo(t.getT2()))
.verifyComplete();
}
Block on create() method
#Test
public void testGetById() {
var entityPojo = new EntityPojo().setName(UUID.randomUUID());
var entity = entityRepository.create(entityPojo).block();
entityRepository.get(e.getId())
.as(StepVerifier::create)
.assertNext(e -> assertThat(e).isEqualTo(entity))
.verifyComplete();
}
Are there any best practices on this? I would prefer second approach, because it's more readable, but may be there are cons of doing it this way, which I'm not aware of?

API Testing / REST Assured Automation Testing Advice and or suggestions

Really looking for some practical advice and general guidance.
Below is the current scenario.
I have an excel document each row would be considered a test with inputs.
There would be hundreds if not thousands of rows.
Lets for example say Row1 would look like
Col1----------|Col2---------------|Col3
TestingUser|TestingSurname|1980/01/01
This needs to me mapped to a JSON object then sent / POST to an API end point.
I then need to assert the data that is coming back to make sure it’s the correct values.
The tools I have looked at is:
ReadyAPI
rest-assured.io
Would you recommend any other tool or framework for this type of testing.
If you have worked with something and you can provide an example that would be great.
I wouldn't be able to provide recommendation as i haven't worked on RestAssured.However below are few advantages of ReadyAPI:
Learning curve is shallow,any Tester will be able to build test
case without dependency on any programming language. ReadyAPI has
inbuild feature to read data from different datasources(DB, XML,
json,csv,excel etc.) and invoke REST endpoint by passing these
fields to Header,query and Json Body of the end point.
The response for each call can be dumped to a file using DataSink option for a
test step for each of the request calls made for the records from the file.
Tool is structured to easily build test Cases with multiple test
Steps. It more like drag and drop to build your test cases.Hierarchy
is Project -> Test Suite -> Test Case -> Test Step.
Easy integration with Jenkins CI/CD pipeline using testRunner with wide
variety of test reporting capabilities. Test reports are available as Allure,
jasper reports, junit Style reporting.
For more technical testers who need more control can use Groovy,javascript
language to build frameworks.
VirtServer and LoadUI are other tools by SmartBear that can be used to mock
services and run performance tests as desired.
I have an important comment to make here, if the file is huge(even 1000 lines) i have seen Ready API struggling as the tool does the heavylifting in the back. Hence would recommend to use groovy script utilizing Java API's for any file operations.
Ok so I have created a class using velocity as a json template engine.
I have created a test and within that test i have a normal java loop.
This will loop through the entire xls, map values and and post to the API.
This is all working as expected.
The problem is the runner displays
Default Suite
Total tests run: 1, Passes: 0,
However the loop does run x amount of times.
How can i update it the when i execute the test its shows total tests run 10 or the same amount that is from the loop.
Hope this makes sense
#Test
public void generatePostData() throws IOException {
Workbook wb = WorkbookFactory.create(new File("data\\sc1.xlsx"));
Sheet sheet = wb.getSheetAt(0);
for (int i = 1; i < 10; i++) {
//Get Excel Data
Cell testNumber = sheet.getRow(i).getCell(1);
System.out.println(testNumber.getNumericCellValue());
//Velocity
VelocityEngine ve = new VelocityEngine();
ve.init();
//get the template
Template t = ve.getTemplate("post.json");
//create context and add data
VelocityContext context = new VelocityContext();
//map data
context.put("tpltestNumber", testNumber);
//render to stringWriter
StringWriter writer = new StringWriter();
t.merge(context, writer);
baseURI = "someURL";
Response response =
given()
.contentType("application/json")
.body(String.valueOf(writer))
.when()
.post()
.then()
.assertThat()
.statusCode(200)
.extract()
.response();
}
}
This is the answer to the question asked in the answers sesction by the reporter of the main question. (How to get the executed excel row count, for total executed test case count)
For that you have to pass the data using a method with DataProvider annotation.
TestNG documentation
DataProvider in TestNG
#DataProvider(name = "dp")
private Object[][] dataProvider() {
Workbook wb;
Sheet sheet = null;
Object[][] excelRowArray = new Object[10][]; //this 10 the row count in the excel file
try {
wb = WorkbookFactory.create(new File("data\\sc1.xlsx"));
sheet = wb.getSheetAt(0);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 1; i < 10; i++) {// Here 10 is the row count in the excel sheet
//Get Excel Data row by row
Cell testNumber = sheet.getRow(i).getCell(1);
System.out.println(testNumber.getNumericCellValue());
// Create a object array with the values taken from a singe excel row
Object[] excelRow = new Object[]{testNumber};
// Add the created object array to the 'excelRowArray'
excelRowArray[i - 1] = excelRow;
}
return excelRowArray;
}
#Test(dataProvider = "dp")
public void generatePostData(Object[] excelRow) {
// Here single excelRow will be passed each time.
// And this will run till all object[] in excelRowArray are finished.
// Total tests executed will be the number of 'excelRow' object arrays in
// excelRowArray. (Or excel row count in the sheet)
//Velocity
VelocityEngine ve = new VelocityEngine();
ve.init();
//get the template
Template t = ve.getTemplate("post.json");
//create context and add data
VelocityContext context = new VelocityContext();
//map data
context.put("tpltestNumber", excelRow); // Here excelRow is used as the value
//render to stringWriter
StringWriter writer = new StringWriter();
t.merge(context, writer);
String baseURI = "someURL";
Response response =
given()
.contentType("application/json")
.body(String.valueOf(writer))
.when()
.post()
.then()
.assertThat()
.statusCode(200)
.extract()
.response();
}

How to write Junit test case for postAbs method of WebClient in Vert.x?

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.

JUnit 4 API Get Handle to a #Test Method

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

Issue with mysql connection while running JUnit test with play2 framework

I'm currently creation JUnit test for a play application. The problem comes when I try to use FakeApplication. I create one in JUnit test but when a test uses the fakeApplication instance, then I got this:
[error] Test controllers.MyClassTest.getMyProperty failed: play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
Here's my Java code in the JUnit test class:
...
#BeforeClass
public static void startFakeApplication() {
Map<String, String> settings = new HashMap<String, String>();
settings.put("db.default.url", "jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8");
settings.put("db.default.driver", "com.mysql.jdbc.Driver");
settings.put("db.default.user", "release");
settings.put("db.default.password", "release");
settings.put("db.default.jndiName", "DefaultDS");
Helpers.start(fakeApplication);
}
...
Then my method to test (notice the dummy run so nothing should cause any trouble):
...
public void getMyProperty() {
Helpers.running (fakeApplication, new Runnable() {
public void run() {
}
});
}
...
I think the problem is a database connection issue, and of course when running play in run mode, everything is fine. If I don't use FakeApplication then it's fine also but I need it.
All the database information in startFakeApplication method are coming from conf/application.conf so they're right.
What is strange is that I also have this line in the output screen when running test:
[info] play - datasource [jdbc:mysql://myhost/releaseDB?characterEncoding=UTF-8] bound to JNDI as DefaultDS
Did I missed something important here ?
Thx
Are you passing your settings map to fakeApplication somewhere? Something like:
FakeApplication fakeApplication = fakeApplication(settings);
An alternative option is to have a separate application-test.conf file and include the following in your build.sbt file:
javaOptions in Test ++= Seq(
"-Dconfig.file=conf/application-test.conf"
)
My framework Acolyte provides a JDBC driver & tools, designed for such purposes (mock up, testing, ...): http://acolyte.eu.org
It's used already in some open source projects (Anorm, Youtube Vitess, ...), either in vanilla Java, or using its Scala DSL.
val jdbcUrl = "jdbc:acolyte:anything-you-want?handler=my-unique-id"
val handler = handleStatement.withQueryDetection(...).
withQueryHandler(/* which result for which query */).
withUpdateHandler(/* which result for which update */).
// Register prepared handler with expected ID 'my-unique-id'
acolyte.Driver.register("my-unique-id", handler);
// then ...
Connection con = DriverManager.getConnection(jdbcUrl);
// ... Connection |con| is managed through |handler|
// Or pass the JDBC url to Play config