I just complete a Java CONSOLE application for Student Management.
I received a test case set (pdf file contains lines follow according to the requirements of the application) build based on the standard program (from my lecturer). You can overview what my app do and what is format of test casenter image description heree set in the attached image below.
The problem is that I want to use test cases for testing my app but instead of manually entering and matching line by line between Console IO and the pdf file => I want to write a program to automatically import and match the data between my jar/program to test cases.
However, I'm not sure how and where to start.
I have tried with google but unit test/white testing is still the thing that takes up all of my search. Hopefully in the process of continuing to try to search with google, someone will give me some suggestions or directions that will be useful to me. Thanks very much.
[My Program]
[Test cases set]
The way I'd do it is to decouple your application from the console so that you can use fake implementations for printing and reading from the console in your tests. "Fake" is the technical term - you can look up "test doubles" to learn about those and other related ideas. This idea is known as dependency injection, or the dependency inversion principle.
The way we do this is to use interfaces. Here's an example of an application that prints some items:
import java.util.List;
public class ItemPrinterApplication {
public ItemPrinterApplication(OutputWriter outputWriter, List<Item> items) {
this.outputWriter = outputWriter;
this.items = items;
}
public void run() {
outputWriter.writeLine("Name, Price");
items.forEach(item -> outputWriter.writeLine(item.name + ", " + item.price));
}
private OutputWriter outputWriter;
private List<Item> items;
}
OutputWriter is the thing responsible for the printing. It's just an interface, so the application doesn't know whether it writes to the console or somewhere else:
public interface OutputWriter {
void writeLine(String line);
}
For completeness, the Item class just holds some data:
public class Item {
public Item(String name, Integer price) {
this.name = name;
this.price = price;
}
public final String name;
public final Integer price;
}
I can then write a test using JUnit that checks that when I run this application, I get the output that I want. I do that by using an implementation of OutputWriter that just writes to a string. That way it's easy to check in the test:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
public class ItemPrinterTest {
#Test
public void itPrintsAListOfItems() {
List<Item> items =
List.of(
new Item("Apple", 50),
new Item("Carrot", 25),
new Item("Milk", 120)
);
FakeOutputWriter fakeOutputWriter = new FakeOutputWriter();
ItemPrinterApplication app = new ItemPrinterApplication(fakeOutputWriter, items);
app.run();
Assertions.assertEquals(
"Name, Price\n" +
"Apple, 50\n" +
"Carrot, 25\n" +
"Milk, 120\n",
fakeOutputWriter.written
);
}
}
and FakeOutputWriter looks like
public class FakeOutputWriter implements OutputWriter {
public String written = "";
#Override
public void writeLine(String line) {
written += line;
written += "\n";
}
}
This gives me confidence that I'm writing the output correctly. In main, though, I want to actually print to the console:
import java.util.List;
public class Main {
public static void main(String[] args) {
OutputWriter outputWriter = new ConsoleOutputWriter();
List<Item> items =
List.of(
new Item("Apple", 50),
new Item("Carrot", 25),
new Item("Milk", 120)
);
new ItemPrinterApplication(outputWriter, items).run();
}
}
and ConsoleOutputWriter does exactly that:
public class ConsoleOutputWriter implements OutputWriter{
#Override
public void writeLine(String line) {
System.out.println(line);
}
}
You could take the same approach for faking reading input. Your interface would have a function that takes no arguments and reads a string:
interface InputReader {
String readLine()
}
so in the tests you could fake that and in main, read using a Scanner or something.
Consider the following code (using Java 1.8.0_102 and JDistLib 0.4.5):
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import jdistlib.Exponential;
import jdistlib.generic.GenericDistribution;
import jdistlib.rng.MersenneTwister;
import jdistlib.rng.RandomEngine;
public class RVs {
public void getEV(GenericDistribution dist, int sampleSize) {
ArrayList<Double> rvs = this.populateArray(dist, sampleSize);
System.out.println(rvs);
}
public ArrayList<Double> populateArray(GenericDistribution dist, int sampleSize) {
RandomEngine randomE = new MersenneTwister(System.currentTimeMillis());
ArrayList<Double> rvs = new ArrayList<Double>();
IntStream.range(0, sampleSize).forEach($ -> rvs.add(dist.random(randomE)));
return rvs;
}
public void test () {
IntStream.range(0, 13).forEach($ -> this.getEV(new Exponential(33.33), 10));
}
}
... implemented like this:
public class CallRVs {
public static void main(String[] args) {
RVs alpha = new RVs();
alpha.test();
}
}
Unfortunately, this always repeats the same sequences of random numbers about 3-4 times.
Before ending up with the code above, I tried this
without setting the RandomEngine explicitly and
without setting the random seed for the RandomEngine to the current time
You would think, creating new RandomEngine instances with seed set to the current time should help, but no:
[22.703723551648405, 6.7092516027839855, 190.59060286639905, 1.8735125522919636, 41.022344668942665, 3.877018716199701, 21.49930713290334, 42.05773014708266, 23.00082916381309, 23.24308297023846]
[22.334558402867305, 1.6401554044082725, 84.11326045120587, 18.165389107596983, 83.13647054950233, 32.72909304649951, 31.453740499105955, 93.5956252958078, 4.040938139470317, 19.99121603725849]
[22.334558402867305, 1.6401554044082725, 84.11326045120587, 18.165389107596983, 83.13647054950233, 32.72909304649951, 31.453740499105955, 93.5956252958078, 4.040938139470317, 19.99121603725849]
[22.334558402867305, 1.6401554044082725, 84.11326045120587, 18.165389107596983, 83.13647054950233, 32.72909304649951, 31.453740499105955, 93.5956252958078, 4.040938139470317, 19.99121603725849]
[79.14217486099653, 41.08293664856576, 7.224345566610367, 127.53056431952126, 80.37600520651415, 38.4618180996009, 0.9904925074615941, 12.20987288657261, 36.530623436560845, 32.1600825790288]
[79.14217486099653, 41.08293664856576, 7.224345566610367, 127.53056431952126, 80.37600520651415, 38.4618180996009, 0.9904925074615941, 12.20987288657261, 36.530623436560845, 32.1600825790288]
[79.14217486099653, 41.08293664856576, 7.224345566610367, 127.53056431952126, 80.37600520651415, 38.4618180996009, 0.9904925074615941, 12.20987288657261, 36.530623436560845, 32.1600825790288]
[79.14217486099653, 41.08293664856576, 7.224345566610367, 127.53056431952126, 80.37600520651415, 38.4618180996009, 0.9904925074615941, 12.20987288657261, 36.530623436560845, 32.1600825790288]
[9.273608510364928, 3.489400227955458, 39.90486871467796, 0.62827300597674, 11.400150691547177, 5.284720630096435, 24.384279251275796, 16.08800783422188, 21.318680903820088, 5.974180125899405]
[9.273608510364928, 3.489400227955458, 39.90486871467796, 0.62827300597674, 11.400150691547177, 5.284720630096435, 24.384279251275796, 16.08800783422188, 21.318680903820088, 5.974180125899405]
[9.273608510364928, 3.489400227955458, 39.90486871467796, 0.62827300597674, 11.400150691547177, 5.284720630096435, 24.384279251275796, 16.08800783422188, 21.318680903820088, 5.974180125899405]
[24.382314535207747, 19.911193724734368, 11.447193297362048, 0.9268859488114056, 18.486786238992774, 29.54231307250453, 17.592849710828943, 26.563616563286097, 19.548355104754787, 4.339118659323733]
[24.382314535207747, 19.911193724734368, 11.447193297362048, 0.9268859488114056, 18.486786238992774, 29.54231307250453, 17.592849710828943, 26.563616563286097, 19.548355104754787, 4.339118659323733]
What is the proper way to prevent such repetitions? Locks (would make everything excessively slow, right?)? "Salting" the seed with some counter or counter with random increment (would be an extremely dirty hack the statistical consequences of which would be unclear)?
Or am I doing something wrong? (I also get "RVs.java:22: warning: [deprecation] random(RandomEngine) in GenericDistribution has been deprecated" which might suggest that this is not the right way to do it.)
I am trying to run a simple re-sequence program using Apache Camel. This program uses the Java DSL to re-sequence incoming Java messages. When I run this program the messages are written to the folder but do not appear to be in any particular order based on the header value or the alphabetical order of the single word in the message body. The files Camel creates are out of order still as if the resequence DSL function did nothing.
How can I get this program to actually order the messages like the Arrays.sort() method would do? Also, how can I get this program to resequence and then aggregate the messages in the correct sort order to a single file?
Here is the program... I call the main Camel route via the other class that has the main method.
import org.apache.camel.builder.RouteBuilder;
public class SortThoseMessages extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:pointA")
.resequence(header("grocery"))
.to("file:target/pointB");
}
}
The class below has main and produces the messages into the queue, pointA.
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.ProducerTemplate;
public class NewSequenceMain {
public static void main(String[] args) {
CamelContext c = new DefaultCamelContext();
try {
c.addRoutes(new SortThoseMessages());
ProducerTemplate template = c.createProducerTemplate();
c.start();
template.sendBodyAndHeader("direct:pointA", "apple", "grocery", 1);
template.sendBodyAndHeader("direct:pointA", "orange", "grocery", 3);
template.sendBodyAndHeader("direct:pointA", "bannanna", "grocery", 2);
Thread.sleep(5000);
c.stop();
} catch(Exception ex) {
System.err.println("Exception thrown -> " + ex);
System.err.println("Now printing stacktrace...");
ex.printStackTrace();
}
}
}
The messages maybe re-sequenced inside the Camel route but not when written to file. To see the re-sequence call the aggregator Java DSL to see the message bodies in the sequence order specified. The messages in the program posted are ordered according to the number of the header. The method call on the ProducerTemplate object reference sets the header as the integer in the last argument to the sendBodyAndHeader() method call.
To see the re-sequencing take effect in a single file as the destination of the Camel route please check out the example below:
import org.apache.camel.builder.RouteBuilder;
public class ReorganizingMessages extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:pointA")
.resequence(header("grocery"))
.to("log://org.apache.camel.howto?showAll=true&multiline=true")
.aggregate().constant(true).completionTimeout(100L).
aggregationStrategy(new StringAggregator())
.to("file:target/pointB");
}
}
The code above uses a custom aggregator Java bean that can be seen below.
import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;
public class StringAggregator implements AggregationStrategy {
#Override
public Exchange aggregate(Exchange old, Exchange new1) {
if (old == null) {
return new1;
}
String oldBody = old.getIn().getBody(String.class);
String newBody = new1.getIn().getBody(String.class);
old.getIn().setBody(oldBody + " " + newBody);
return old;
}
}
I'm trying to analyse some bits of Java-code, looking if the code is written too complexly. I start with a String containing the contents of a Java-class.
From there I want to retrieve, given a function-name, the "inner code" by that function. In this example:
public class testClass{
public int testFunction(char x) throws Exception{
if(x=='a'){
return 1;
}else if(x=='{'){
return 2;
}else{
return 3;
}
}
public int testFunctionTwo(int y){
return y;
}
}
I want to get, when I call String code = getcode("testFunction");, that code contains if(x=='a'){ ... return 3; }. I've made the input code extra ugly, to demonstrate some of the problems one might encounter when doing character-by-character-analysis (because of the else if, the curly brackets will no longer match, because of the Exception thrown, the function declaration is not of the form functionName{ //contents }, etc.)
Is there a solid way to get the contents of testFunction, or should I implement all problems described manually?
You need to a java parser. I worked too with QDox. it is easy to use. example here:
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import java.io.File;
import java.io.IOException;
public class Parser {
public void parseFile() throws IOException {
File file = new File("/path/to/testClass.java");
JavaProjectBuilder builder = new JavaProjectBuilder();
builder.addSource(file);
for (JavaClass javaClass : builder.getClasses()) {
if (javaClass.getName().equals("testClass")) {
for (JavaMethod javaMethod : javaClass.getMethods()) {
if (javaMethod.getName().equals("testMethod")) {
System.out.println(javaMethod.getSourceCode());
}
}
}
}
}
}
Have you considered using a parser to read your code? There are a lot of parsers out there, the last time I worked on a problem like this http://qdox.codehaus.org made short work of these kinds of problems.
This is a sample program:
public class FunctionalTest {
public int f(int r) {
int result = r * 5;
return result;
}
public static void main(String[] args) {
FunctionalTest funct = new FunctionalTest();
System.out.println(funct.f(5));
}
}
I'm a beginner.
How to write a functional test for this code?
How to write functional tests? Do I need to TestNG?
Is it enough to write the examination method?
Could someone explain to me and write a sample functional test for this program?
Well, if you're specifically asking for functional testing, there's not much you can do with that code snippet. You can do a unit test from the f method using JUnit like this:
#Test
public void testF(){
FunctionalTest t1 = new FunctionalTest();
assertEquals((t1.f(1) % 5), 0); //checks that is getting multiplied by 5.
}
However, you want functional testing, so by running your compiled app and assessing the result you're testing your app functionality by multiple units (AKA integration): your f method and your main method.
Regards!
First of all, you need to have a clear definition of contract you want to verify. From the code, I assume it is something like "the method should return the number equal to argument multiplied by 5".
TestNG, JUnit or other test frameworks is not mandatory for your case. The test may look like:
public void testF() {
int arg = 5;
int result = new FunctionalTest().f(arg);
assert result == arg * 5;
}
Also please keep in mind that to use assert you need JVM started with -ea flag.
Beware the terms you used:
the functional testing provide values to your user/customer
That implies:
black box testing: you have to test your whole system (hard+soft)
the test should target your user/customer needs (explicit report or test)
You can use whatever you want to test the feature (from unit test to jbehave).
In your case (using JUnit 4 and AssertJ):
import org.assertj.core.api.Assertions;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/*
As an user
I want have 25 whatever I sent
*/
public class NumberGenerationTest {
private static final String PATH = "directory of your class file";
private InputStream stdout;
/* Nominal case */
#Test
public void shall_return_number_25_when_called_with_5() throws Exception {
when_I_call_FunctionalTest_with("5");
then_it_returns("25");
}
/* Nominal case or potential error case */
#Test
public void shall_return_number_25_when_called_with_10() throws Exception {
when_I_call_FunctionalTest_with("10");
then_it_returns("25");
}
/* Nominal case or potential error case */
#Test
public void shall_return_number_25_when_called_with_ABC() throws Exception {
when_I_call_FunctionalTest_with("ABC");
then_it_returns("25");
}
private void when_I_call_FunctionalTest_with(String parameter) throws Exception {
ProcessBuilder builder = new ProcessBuilder("java" ,"-classpath", PATH,"FunctionalTest" , parameter);
builder.redirectErrorStream(true);
Process process = builder.start();
stdout = process.getInputStream ();
}
private void then_it_returns(String expectedResult) throws Exception {
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
String line = reader.readLine ();
Assertions.assertThat(line).isNotNull();
Assertions.assertThat(line).isEqualTo(expectedResult);
}
}
It seems you have an error in your main() ... or not.