Hi this is the first time im trying out unit testing in java using eclipse.
So when i test my class, it requires user input. Lets say a command called "add hello", so that it will create a new textfile and add the word "hello" to it. Then i want to test a function called getAllLines which returns "hello" and compare it with assert.
My main problem is how to simulate user input to console via junit test. This is what i tried but its not working..
private void performUserInput(String strInput){
ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
System.setIn(in);
}
private void releaseUserInputToSystem(){
System.setIn(System.in);;
}
#Test
public void testSearchingInEmptyFile() {
TextBuddy textBuddy = new TextBuddy("file.txt");
textBuddy.run();
performUserInput("add little brown fox");
releaseUserInputToSystem();
assertEquals("little brown foxx", "asd");
}
It seems to me like the code never reaches assert.
edit----------------------------------------------
After debugging, its getting stuck here
private String[] getCommandAndArgs(){
String[] splitCommand = scanner.nextLine().split(" "); //<<STUCK HERE
printNewLine();
return splitCommand;
}
With the Unit-Test you should rather test single Methods (units) of your TextBuddy Class. You probably have a method which check the commands (add, remove, whatever you have). Write Unit Tests for those e.g.:
#Test
public void testCommandAdd() {
TextBuddy tb = new TextBuddy ();
int command tb.parseCommand("add hello");
assertThat(command,is(TextBuddy.ADD));
}
#Test
public void testCommandRemove() {
TextBuddy tb = new TextBuddy ();
int command tb.parseCommand("remove hello");
assertThat(command,is(TextBuddy.REMOVE));
}
Then write tests for each command, e.g. that a file was written/deleted whatever:
#Test
public void testWriteFile() throws SQLException {
TextBuddy tb = new TextBuddy ();
tb.writeFile("file.txt", "hello");
File f = new File("file.txt");
String content = readFile(f);
assertThat(content,is("hello"));
}
Always test single units of your program with small Unit Tests. Later you can write bigger Tests that check if your hole Program works.
If you don't want to expose your Methods with the public modifier, you can still test them - the simplest way is makeing them package-private and have your tests the same package (they can and should be in a differnet src-folder)
e.g. for a Class with the package com.yourpackage like this
src/com/yourpackage/YourClass.java
You could store your test in
test/com/yourpackage/YourClassTest.java
Then you can access package-private Methods.
Or you use Reflection to access and test a private Method, see here and here
A unit test is all about automation and should not rely on user input. If you want to test a user input mechanism, you should write a test that simulates a user entering the input to be tested (e.g. using Selenium for front end testing a web application). If you want to test behavior based on input, you should contruct tests that enter all possibilities that shall be tested automatically and validate the respective correct behavior of your application/program/functionality.
If TextBuddy.run() is specified to read something from System.in, it looks like a good idea to redirect System.in before the call to run():
performUserInput("add little brown fox");
textBuddy.run();
releaseUserInputToSystem();
But maybe you could improve your TextBuddy to be more testable by adding the input stream to read from as a parameter to the run method:
public void run(InputStream in) {
// use parameter in instead of System in...
}
/**
* Convenience method to run with System.in
*/
public void run() {
run(System.in);
}
In your test, call run(InputStream):
ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
textBuddy.run(in);
You could also add an out parameter to be able to redirect the output of your tested method.
I agree with #LarsGendner you should mock (do some simulate or fake things) for the input task. You can use some technique that provides input to coverage at least for some part of this code (for example TextBddy). In this case, I can suggest three approaches.
static inputs use this approach if you need to have some text samples derived from empirical testing. You can use this form model some typical behavior from existing users;
random string generator use this approach to do string generation from scratch (you can combine this approach with static input)
framework (or library) to extend jUnit capability in towards of data mining or artificial intelligence such as genetics algorithms, neural networks and so on.
In my onion the last technique is more sophisticate. So, you should evaluate and perform a thread-off to decide which parts should be testing and which should be the code coverage that you need. Notice, that mocking some input task according to human behavior it is not trivial task.
Regarding your original code, when you execute textBuddy.run(); it will lock expecting user input, so the next line (performUserInput("add little brown fox"); which does provide the input it is waiting for) is never executed.
So, to make that code work, you should call performUserInput("add little brown fox"); before calling textBuddy.run():
#Test
public void testSearchingInEmptyFile() {
TextBuddy textBuddy = new TextBuddy("file.txt");
performUserInput("add little brown fox"); // changed these two lines
textBuddy.run(); // switched their order
releaseUserInputToSystem();
assertEquals("little brown foxx", "asd");
}
Another approach is to use threads: execute textBuddy.run() in one thread and performUserInput("add little brown fox") in other. It is probably best to avoid this, though, as threads may make your tests way more difficult to maintain.
Full demo code:
public class TextBuddyTest {
private InputStream performUserInput(String strInput) {
InputStream originalSystemIn = System.in;
ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
System.setIn(in);
return originalSystemIn;
}
private void restoreSystemInputStream(InputStream originalSystemIn) {
System.setIn(originalSystemIn);
}
#Test
public void testSearchingInEmptyFile() {
// setup
InputStream defaultSystemIn = performUserInput("add little brown fox");
TextBuddy textBuddy = new TextBuddy("file.txt");
// execute
textBuddy.run();
// verify
assertEquals("[add, little, brown, fox]", textBuddy.getWhatWasInput());
// teardown
restoreSystemInputStream(defaultSystemIn);
}
static class TextBuddy { // created for this demo
Scanner scanner = new Scanner(System.in);
String whatWasInput;
public TextBuddy(String s) { }
public void run() { this.whatWasInput = Arrays.toString(getCommandAndArgs()); }
private String[] getCommandAndArgs() { return scanner.nextLine().split(" "); }
public String getWhatWasInput() { return whatWasInput; }
}
}
Related
I am quite a new coder in Java, I have already used it before but without going deep into it, but now that I learned the basic I am searching for a way to be more efficient in my way of coding, so I ask how could I do lines of code to run one after another each time I use a certain word, for example, I would like my code to run several fighting commands that I premade using only the word "fight" in my code
All you need to do is set up a scanner that waits for a string input after which is process the string received through the scanner and if said string is "fight" then call the fight method.
Like this:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String command = in.next();
in.close();
ProcessCommand(command);
}
static void ProcessCommand(String command) {
if (command.equalsIgnoreCase("fight")) {
fight();
}
}
static void fight() {
// Do Stuff..
}
Hope this helps! :D
This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 4 years ago.
I want to test method setDay() using arguments [-1,0,24,2,32].
I know that Scanner reader can be
String test="-1 0 24 2 32";
Scanner reader=new Scanner(test);
The main problem is infinite loop and void method. How can we test this kind of code? Here is example code:
public NameOfTheDay(){
int day=1;
}
{...}
public void setDay(Scanner reader) {
while (true) {
System.out.print("Day: ");
String input = reader.nextLine();
if (input.matches("\\d{2}")) {
int day = Integer.parseInt(input);
if (day > 0 && day < 32) {
this.day = day;
return;
}
}
System.out.println("Wrong day. Try again.");
}
}
Thanks for the answer.
How can we test this kind of code?
You cannot.
unittest verify the public observable behavior of your code under test where "public observable behavior" is any rreturn value or communication with dependencies.
Communication with dependencies is checked with test doubles which we (usually) create using a mocking framework and which we inject into the code under test.
A major prerequest is that you code cleanly incorporates Single Responsibility/Separation of Concerns pattern.
Your code does not return anything and has no possibility to replace the dependencies of interest (here System.out) because it mixes business logic with user interaction.
Some may argue, that you can assign a test double to System.out or use PowerMock to replace dependencies but IMHO this is just a surrender to your bad design and will not pay off as your program grows.
I will not focus on the contents of your method, but just on the question on how to unit test a method expecting a Scanner object as parameter.
The easy answer is: Provide your test input data as a String, and build a scanner around it, like this:
#Test
public void testSetDay_positive() {
String testInput = "23\n";
Scanner testScanner = new Scanner(testInput);
NameOfTheDay notd = new NameOfTheDay();
notd.setDay(testScanner);
Assert.assertEquals(23, notd.getDay()); // or whatever condition to test
}
Now it gets harder. Perhaps you want to test an invalid input first, and make sure the second input is used then?
#Test
public void testSetDay_negative_then_positive() {
String testInput = "999\n23\n"; // two lines of input here
Scanner testScanner = new Scanner(testInput);
NameOfTheDay notd = new NameOfTheDay();
notd.setDay(testScanner);
Assert.assertEquals(23, notd.getDay()); // or whatever condition to test
}
If you want to test if the error message is written to System.out, you would have to replace that with a custom stream to test afterwards:
ByteArrayOutputStream mockOut = new ByteArrayOutputStream();
PrintStream newOut = new PrintStream(mockOut);
System.setOut(newOut);
// execute test from above
Assert.assertTrue(new String(mockOut.toByteArray(), "UTF-8").contains("Wrong day. Try again."));
Still, most comments to your question contain valuable input (move validation to an extra method etc.) which should be considered.
My Java application consists of two parts:
core libraries (classes, interfaces, etc)
command line interface (CLI), which uses the core libraries
For 1. I use JUnit for unit testing, but what would you do for 2.?
How can I create automated tests for a command line interface?
I had the exact same problem, landed here and didn't find a good answer, so I thought I would post the solution I eventually came to as a starting point for anyone who lands here in the future.
I wrote my tests after the CLI (shame on me, I know), so first I made sure the CLI was written in a testable way. It looks something like this (I've omitted the exception handling and simplified a lot to make it more readable):
public class CLI {
public static void main(String... args) {
new CLI(args).startInterface();
}
CLI(String... args) {
System.out.println("Welcome to the CLI!");
// parse args, load resources, etc
}
void startInterface() {
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String[] input = sanitiseInput(consoleReader.readLine());
if (input[0].equalsIgnoreCase("help") {
help();
} else if (input[0].equalsIgnoreCase("exit") {
break;
} else if (input[0].equalsIgnoreCase("save") {
save(input);
} else {
System.out.println("Unkown command.");
}
}
}
String[] sanitiseInput(String rawInput) {
// process the input and return each part of it in order in an array, something like:
return rawInput.trim().split("[ \t]+");
}
void help() {
// print help information
System.out.println("Helpful help.");
}
void save(String[] args) {
// save something based on the argument(s)
}
}
On to testing. CLI is not a part of the public libraries, so it should be protected from library users. As is mentioned here, you can use the default access modifier to make it package private. This gives your tests full access to the class (as long as they are in the same package) while still protecting it, so that's that taken care of.
Writing a method for each command accepted by the CLI allows JUnit tests to almost perfectly simulate user input. Since the object won't read from stdin until you call startInterface(), you can simply instantiate it and test the individual methods.
First, it's good to test that the raw input is being correctly sanitised, which you can do trivially by writing JUnit tests for sanitiseInput(). I wrote tests like this:
#Test
public void commandAndArgumentsSeparatedBySpaces() throws Exception {
String[] processedInput = uut.sanitiseInput("command argument1 argument2");
assertEquals("Wrong array length.", 3, processedInput.length);
assertEquals("command", processedInput[0]);
assertEquals("argument1", processedInput[1]);
assertEquals("argument2", processedInput[2]);
}
It's easy to cover some edge cases too:
#Test
public void leadingTrailingAndIntermediaryWhiteSpace() throws Exception {
String[] processedInput = uut.sanitiseInput(" \t this \twas \t \t a triumph \t\t ");
assertEquals("Wrong array length.", 4, processedInput.length);
assertEquals("this", processedInput[0]);
assertEquals("was", processedInput[1]);
assertEquals("a", processedInput[2]);
assertEquals("triumph", processedInput[3]);
}
Next we can test the invididual command methods by monitoring stdout. I did this (which I found here):
private CLI uut;
private ByteArrayOutputStream testOutput;
private PrintStream console = System.out;
private static final String EOL = System.getProperty("line.separator");
#Before
public void setUp() throws Exception {
uut = new CLI();
testOutput = new ByteArrayOutputStream();
}
#Test
public void helpIsPrintedToStdout() throws Exception {
try {
System.setOut(new PrintStream(testOutput));
uut.help();
} finally {
System.setOut(console);
}
assertEquals("Helpful help." + EOL, testOutput.toString());
}
In other words, substitute the JVM's out with something you can query just before the exercise, and then set the old console back in the test's teardown.
Of course, CLI applications often do more than just print to the console. Supposing your program saves information to a file, you could test it as such (as of JUnit 4.7):
#Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
#Test
public void informationIsSavedToFile() throws Exception {
File testFile = tempFolder.newFile();
String expectedContent = "This should be written to the file.";
uut.save(testFile.getAbsolutePath(), expectedContent);
try (Scanner scanner = new Scanner(testFile)) {
String actualContent = scanner.useDelimiter("\\Z").next();
assertEquals(actualContent, expectedContent);
}
}
JUnit will take care of creating a valid file and removing it at the end of the test run, leaving you free to test that it is properly treated by the CLI methods.
For any CLI you can use BATS (Bash Automated Testing System):
The test-specification from the docs is a script-file like example.bats:
#!/usr/bin/env bats
#test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
#test "addition using dc" {
result="$(echo 2 2+p | dc)"
[ "$result" -eq 4 ]
}
When using the bats command to execute and the output look like this:
$ bats example.bats
✓ addition using bc
✓ addition using dc
2 tests, 0 failures
See related tag for more questions: bats-core
I know there are several question about void-method Unit-Testing, but my question is different.
I'm learning java, so my boss give me some tasks with different requirements on my tasks.
In my actual task, there is a requirement which says, the jUnit test must cover >60%. So I need to test a very simple method to reach this 60%. The method is the following:
public void updateGreen() {
// delete this outprint if the Power Manager works
System.out.println(onCommand + "-green");
// p = Runtime.getRuntime().exec(command + "-green");
// wait until the command is finished
// p.waitFor();
}
Because of intern problems, I can't execute the command with the Runtime task. So there is only a System.out in this method.
I've multiple methods like that, so tests for this method will cover over 10% of my whole code.
Is it useful to test such a method? When yes, how?
If there is a lot of such methods, the thing which you might want to test here is that updateScreen() uses the right string, "some-command-green" and that the System.out is being invoked. In order to do this you might want to extract System.out into an object field and mock it (i.e. with Mockito's spy()) to test the string that was provided to println.
I.e.
class MyClass{
PrintStream out = System.out;
public void updateGreen() { ... }
}
In test:
#Test
public void testUpdate(){
MyClass myClass = new MyClass();
myClass.out = Mockito.spy(new PrintStream(...));
// mock a call with an expected input
doNothing().when(myClass.out).println("expected command");
myClass.updateGreen();
// test that there was a call
Mockito.verify(myClass.out, Mockito.times(1)).println("expected command");
}
You could return true if the method ran successfully and false otherwise. It would be easy to test for this.
You could also test the output of this method, as described here:
Should we unit test console outputs?
But in my experience, it is much better to have methods return an optimistic or pessimistic value (true/false, 1/0/-1 etc) to indicate their status.
You can also write a getter method for the onCommand flag:
public string getFlag(){
// some logic here
return "green";
// otherwise default to no flags
return "";
}
You could test that onCommand + "-green" has been written to System.out by using the System Rules library.
I am in a project now that is using JUnit as a framework to test engineering data (ref: last question Creating a Java reporting project -- would like to use JUnit and Ant but not sure how)
Since a picture (err a code block) tells a 1,000 words, so let me paste my loop:
JUnitCore junit = new JUnitCore();
RunListener listener = new RunListener();
junit.addListener(listener);
[...]
for (AbstractFault fault : faultLog) {
theFault = fault;
Result result = junit.run(GearAndBrakeFaultLogReports.class);
for (Failure f : result.getFailures()) {
output.println(log.getName());
output.println(fault.getName());
output.println(HelperFunctions.splitCamelCase(f.getDescription()
.getMethodName()));
output.println(f.getMessage());
output.println();
}
}
As you can see, I am running the "junit.run" many times (for each fault in the log).
However, if any one of my tests fires a fail() I don't want to repeat that test. In other words, if there are 50 faults in a log, and in fault #1 a test fails, I don't want to attempt that test in the 49 future faults I am looping through.
Here is an example test:
private static boolean LeftMLGDownTooLongFound = false;
#Test
public final void testLeftMLGDownTooLong() {
if (!LeftMLGDownTooLongFound
&& handleLDGReportFaults(false)
&& theFault.getName().equals(FaultNames.LDG_LG_DWN_TIME.toString())) {
assertNotGreater(getPCandRecNum(), 8f, ldgFault.getLeftStrutUpTime());
LeftMLGDownTooLongFound = true;
}
}
Currently, do to this, I am making a static bool that is set to false at first, but switches to true after the first assertion. Not sure if this works, but its the idea. I don't want to do this for every single test (100's of them).
Is there any public function, method, or way in the JUnitCore or Runner class that I can flag it so a test never runs more than once after a fail() is called?
Ah, figured it out. To do this, I need to implement a way to find the failed tests, then in the #Before area, ax out of the test. Here is what I added.
#Rule public TestName name = new TestName();
#Before
public void testNonFailedOnly() {
Assume.assumeTrue(!failedTests.contains(name.getMethodName()));
}
private static List<String> failedTests = new ArrayList<String>(256);
#Rule
public TestWatcher watchman = new TestWatcher() {
/* (non-Javadoc)
* #see org.junit.rules.TestWatcher#failed(java.lang.Throwable, org.junit.runner.Description)
*/
#Override
protected void failed(Throwable e, Description description) {
super.failed(e, description);
failedTests.add(description.getMethodName());
}
};
It does add about 1.5 seconds of overhead, which sucks... but better than the alternative!!
Anyone have ideas on how to optimize this? I believe the overhead is from the TestWatcher, don't think it from the arraylist.
I used a Java Class that every test extends.
In the #Before of this class I set a boolean hasPassed = false;
At the end of every #Test method I set this variable hasPassed = true;
In the #AfterMethod you can then check the variable.
If your test causes an exception, it wont reach the end and the variable is still false.