How to test method that only print out message - java

I have method that print winner in the class Game:
public void getWinner(String winner){
System.out.println("WINNER IS " + winner);
}
How can I test this method so far I have:
Game gm = new Game(); // it is declared in #before
#test
public void test(){
ByteArrayOutputStream outContent = new ByteArrayOutputSystea();
System.setOut(new PrintStream(outContent));
gm.getWinner(Bob);
assertEquals("WINNER IS Bob",outContent.toString());
}
I have an error message that say
org.unit.ComparisonFailuter expected:<WINNER IS Bob[]> but was: <WINNER IS Bob[
]>
Well could you please give me a tip on how to test getWinner method

omg don't do it! you don't have to test the println method. guys from sun and oracle have already done that - you can be sure it works. all you have to test is that you pass the right string to to that method. so refactor your code and create a function that return the desired string and test only that method by simple string comparison

From the documentation:
public void println(String x)
Prints a String and then terminate the line. This method behaves as though it invokes print(String) and then println().
So when you print the line in the method, there's a line separator after it which is defined as so:
The line separator string is defined by the system property line.separator, and is not necessarily a single newline character ('\n').
So you can either add a hardcoded line separator to your expected output, or you could use the following code to get the separator for the current system and append that.:
System.getProperty("line.separator");

A mockist approach:
#Test
public void testGetWinner()
{
// setup: sut
Game game = new Game();
PrintStream mockPrintStream = EasyMock.createMock(PrintStream.class);
System.setOut(mockPrintStream);
// setup: data
String theWinnerIs = "Bob";
// setup: expectations
System.out.println("WINNER IS " + theWinnerIs);
// exercise
EasyMock.replay(mockPrintStream);
game.getWinner(theWinnerIs);
// verify
EasyMock.verify(mockPrintStream);
}
Pro: You don't need to care what System.out.println() does, in fact if the implementation changes your test will still pass.

I think you try to compare to strings with == when you should use .equals(). The strings are stored i a constant pool, but in this case you read a string from somewhere else, which not nescessarily goes into the constant pool.
Try
assertTrue(outContent.toString().equals("WINNER IS Bob"));
or whatever your testing library calls it.
which looks for the characters in the String instead of the memory address ("ref") of the String.

Related

jUnit for file reader

I got a method that read from a txt file and populate a list with words that are exists in the file.
the method is calculate and return Most Repeated Word.
If I want to write a jUnit for that. how should I test the corectess of that method given the fact the file is changing frequentaly.
As #jaibalaji wrote, JuintTests should not depend on resources outside of the JVMs memory.
So the first step must be to make your code under test (cut) independent of the actual file.
I got a method that read from a txt file and populate a list with words that are exists in the file. the method is calculate and return Most Repeated Word.
In this sentences you mention 3 responsibilities:
reading a file
populating a list
find Most Repeated Word
You should split this method so that you ed up with smaller classes with the one responsibility each only.
class TextAnalyser{
private final WordListBulder wordListBulder; // converts String into List of words
private final WordCountAnalyser wordCountAnalyser;
public TextAnalyser(WordListBulder wordListBulder, WordCountAnalyser wordCountAnalyser){
this.wordListBulder = wordListBulder;
this.wordCountAnalyser = wordCountAnalyser;
}
public String findMostRepeatedWordIn(MyFileReader myFileReader){
String fileContent = myFileReader.readContent();
List<String> wordList = wordListBulder.crerateWordListFrom(fileContent);
return wordCountAnalyser.findMostRepeatedWordIn(wordList);
}
This code is too simple to fail and don't need to be UnitTested. Module- and/or Acceptance-Tests will show that this works.
Now the behavior to test is in the class WordCountAnalyser. And it has a simple t "fake" input which leads to a deterministic testable output.
The file should be a parameter of the method or an instance field of the class of this method.
In this way, you can unit test the method by providing a file which you master the data and you know how assert them.
For example with the parameter way :
public String findMostRepeatedWork(File file){
...
}
And so you could unit it easily :
#Test
public void findMostRepeatedWork(){
// fixture
File myTestFile = ...;
// action
new MyClassToTest.findMostRepeatedWork(myTestFile);
// assertion
...
}
Junit is not intended for any test that is taking resources(file, dB or network)

Printing String in reverse using three pre-given methods?

I need to write a printBackwards() method, using three pre-given methods first, rest and length. printBackwards() method needs to take String as a parameter and prints each letter of that string on the console, but each letter needs to be printed on new line and in reverse order. So if the String is House, the output should be:
e
s
u
o
H
In this exercise, we should use recursion and if-else statements. No arrays, no other (familiar) String method, no while and for loop.
I have done a little bit, I know it is not correct, but that is how much I managed to do. I dont understand how to write code so the method can return letters before letter e. How to use recursion here ?
public class Recurse {
public static void main(String args[]){
System.out.println(printBackwards("House"));
}
//printBackward: takes a String as a parameter and prints letters of the String,
// one on each line, but backwards
public static String printBackwards(String s){
if (length(s) == 1){
return s;
} else {
return printBackwards(rest(s));
}
}
// first: returns the first character of the given String
public static char first(String s) {
return s.charAt(0);
}
// last: returns a new String that contains all but the
// first letter of the given String
public static String rest(String s) {
return s.substring(1, s.length());
}
// length: returns the length of the given String
public static int length(String s) {
return s.length();
}
}
Because this is a homework question, I'll leave as much as possible to you, so you learn.
Consider these two facts:
You must print the first character after you have printed the rest
If the string is empty, print nothing
Use these two facts are enough to build a recursive method.
Point 2. is the terminating condition. It's best to code this first.
Point 1. is the main method body, where printing the rest is done using recursion
Once you have your terminating condition and your recursive structure (often, a pre-order or a post-order operation), you can build a recursive method.
Note also the name of the method printBackwards() (not backwards()). That is, the method does the printing; it doesn't return the String backwards.
So, translating the above into pseudo-code (which in this case is practically the code):
if the string is empty do nothing
call self with the rest of the string
print the first character
First of all you need to print the output within the printBackwards function, so the main will look like this:
public static void main(String args[])
{
printBackwards("House");
}
Second, is the way recursion works. If you want it to be executed in the ascending order, you should do stuff before the self function call. Otherwise, in case of descending execution order, you code should be executed after the self calling function. These are the basic principles of the recursion function.
In this case, let's try to build the answer.
First, we need to handle the stop condition, which should be always written before the self calling function. The best and most common stop condition, is to reach to the end of something, in this case it is when we get an empty string, in all other cases we need to call the self function with a slight of a change, in this case it will be providing the rest of the string to the function:
if ( !length(s) )
{
//stop the recursion
return;
}
else
{
printBackwards(rest(s));
}
When you reach the stop recursion statement, from this point and on, it will close all the opened self function executions, therefor will go backward.
This is the perfect state of what we need to achieve, print the letters backward and because on each state of the printBackwards execution, we have sliced the string a bit from the left letters, it means that the first letter is the one we need.
For example, in case of the string House the last call of the printBackwards function will be when the s variable will hold the e value, because it is one stem from being cut-off to an empty string, when we reach the stop condition. In this case we want to print it out, but in the self call before this one, the s variable will hold the value se, because it is one step before cutting the first letter. So, we not want to print the whole value, but only the first letter of it, like this:
System.out.println(first(s));
Combining everything together, will result the following implementation:
public static String printBackwards(String s)
{
if ( !length(s) )
{
//stop the recursion
return;
}
else
{
printBackwards(rest(s));
System.out.println(first(s));
}
}
Hope, I explained it clearly.
Good luck!

Cannot add new object to a set, values come from a file

I am trying to create a public instance method that takes no arguments and returns no values. It is required to get an input from a user to select a file, this part I have no issues with. The method needs to make use of the BufferReader and Scanner Objects. So that it can read the file selected. For each line that is read, a new object should be created and its instance variables set using the values found in the file.
That object that is created should then be added to a list. This is where I am having issues, it won't let me add the new object to the list. Below is my code:
public void readInEntrants()
{
String pathname = OUFileChooser.getFilename();
File aFile = new File(pathname);
Scanner bufferedScanner = null;
Set<Entrant> entrantSet = new HashSet<>();
try
{
String currentEntrantLine;
Scanner lineScanner;
bufferedScanner = new Scanner(new BufferedReader(new FileReader(aFile)));
while (bufferedScanner.hasNextLine())
{
currentEntrantLine = bufferedScanner.nextLine();
lineScanner = new Scanner(currentEntrantLine);
lineScanner.useDelimiter(" ");
currentEntrantLine = lineScanner.next();
entrantSet.add(new Entrant(currentEntrantLine)); // <----- Here is where I am having trouble. It won't let me add the new object to the class Entrant
}
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
finally
{
try
{
bufferedScanner.close();
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
}
return entrantSet;
}
I'm not sure what to do. Could anyone see what I am doing wrong?
Sorry for got to add that it is a compilation issue, it will not compile properly.
Use an IDE ,I bet you dont (otherwise it would mark compilation error immediatly with red -> you use return in void method ) and in this case you would see other errors.
(off: this would go to comment section however under 50reputation I am not allowed to do that. Stackoverflow should change this imo. )
First of all:
You marked function readInEntrants as public void so you can't use return inside.
You could either remove return entrantSet; instruction or change function definition to public Set<Entrant> readInEntrants.
Concerning problem you have:
Basing on comment you left on beatrice answer I think you have only parameterless constructor for 'Entrant' class, while you try to create it passing string as parameter.
new Entrant(currentEntrantLine)
What you need to do is define Entrant class constructor that accept String as it's argument. For example:
public Entrant(String dataToParse)
{
// here you parse data from string to entrant fields
}
On the side:
You use bufferedReader to read entire file line at once and that's ok, but then you define Scanner lineScanner to iterate through line elements and then use it only once.
This way for file... let's say:
One Two Three
Four Five Six
Your while loop would work like this:
Store "One Two Three" inside currentEntrantLine.
Create scanner that'll work on "One Two Three", and set it to use space as delimiter.
Use .next to "Finds and returns the next complete token" (see documentation) and then store value inside currentEntrantLine. This way contents of currentEntrantLine is "One". Not entire line.
In next iteration you would have scanner working on "Four Five Six" and "Four" as currentEntranceLine content.
It seems the constructor of entrant class does not have any argument. Pass String as an argument type in the constructor to set the String field inside the Entrant class .

Test a void method with conditioned loop using mockito

I have following method which asks for user input until valid user credentials are entered.It then generates id for that user and sets registered =TRUE.
1.How can I check the value of local variable "registered" from my unit test?
2.How can I assert in my test that while loop executed until "registered" became TRUE?
private void register() {
boolean registered=false;
while(!registered){
try {
String uname =this.read("User Name : ");
char password[] = this.readPassword();
String serverURL = this.read("Server URL : ");
if(!uname.isEmpty() && password!=null && !serverURL.isEmpty()){
registered=this.getUID(uname,password,serverURL);
}
if(registered==false)
System.out.println("\nPlease verify your details and try again!\n");
} catch (UnsupportedEncodingException e) {}
catch(Exception e){}
}
System.out.println("Successful");
}
I have come across usage of ArgumentCaptor to capture variables that a method to be tested, uses to invoke another methods.
e.g verify(mockObj).intArgumentMethod(argument.capture());
However I am not passing variable "registered" to any other method otherwise i would have captured it.
You cannot
By verification:
The loop invariant is that registered is false. So the loop is not entered if it is true
The loop is exited
at the bodies start (in this case it is true)
if a Throwable is thrown, that is not caught by 'catch(Exception e)' (in this case it might be anything)
Anyway - review your testing strategy:
a function has input parameters and output parameters
the input should be part of the fixture:
this.read("User Name : ")
this.readPassword()
this.read("Server URL : ")
this.getUID(uname,password,serverURL) // this may also be viewed as output
the output should be part of the assertions
System.out.println(...)
The input can be set up by creating anonymous sub classes, e.g.
fixture = new YourClass {
public String read(String prompt) {
return mockedString;
}
...
};
The output can be captured/asserted by a Junit Rule, e.g. StandardErrorStreamLog
Mockito is not needed with this example method.
Don't test the implementation details, test the behavior given certain input. If the registered variable is supposed to be some sort of output then it shouldn't be a local variable.
One design I like is to use method objects, it is possible to pass arguments at object creation, and an object method can have multiple return values.
class Registrator {
Registrator(...) { /* assigning needed field */ }
void register() { /* logic that will mutate internal fields */ }
boolean registered() { return registered; }
long triesCount() { return triesCount; }
// ...
}
And one can adapt the code to use a Report object, on which the register method can append success / failure / more details like reasons / etc.
And the test would be much more easy to write.

Convert logger.debug("message: " + text) to logger.debug(message: {}", text)

I am trying to find the best way to address the issue of redundant string concatenation caused by using code of the following form:
logger.debug("Entering loop, arg is: " + arg) // #1
In most cases the logger.level is higher than debug and the arg.toString() and the string concatenation are a waste that user up cpu cycles and briefly use up memory.
Before the introduction of varargs the recommended approach was to test the logger level first:
if (logger.isDebugEnabled())
logger.debug("Entering loop, arg is: " + arg); // #2
But now the preferred form is
logger.debug("Entering loop, arg is: {}", arg); // #3
It is not very difficult to prefix each logger.debug with if (logger.isDebugEnabled()) (and its equivalent for the other methods) in a script, but I am trying to find the best way to convert the first form to the third.
Any suggestions? The challenge is to insert the correct number brace pairs {} in the format string. I wish logback would append the remaining arguments not covered by the placeholder at the end but I cannot find a reference that it does that.
As an alternative, I am thinking to write a class Concatenator as pasted at end and convert the first form to
logger.debug(new Concatenator("Entering loop, arg is: ", arg)); // #4
The Concatenator class delays the call to arg.toString() and string concatenation until the logger calls toString(), thereby avoiding both if the logger is at a higher filter level. It does add the overhead of creating an Object[] and a Concatenator but that should be cheaper than the alternative.
Questions:
I think this conversion (#1->#4 -- replace + with , and enclose in new Contatenator(...)) is much easier. Is there something I am missing?
Am I correct that #4 is much better than #1?
public class Concatenator {
final Object[] input;
String output;
public Concatenator(Object... input) {
this.input = input;
}
public String toString() {
if (output == null) {
StringBuffer b = new StringBuffer();
for (Object s : input) b.append(s.toString());
output = b.toString();
}
return output;
}
public static void main(String args[]) {
new Concatenator("a", "b", new X());
System.out.println(new Concatenator("c", "d", new X()));
}
}
class X {
public String toString() {
System.out.println("X.toString");
return super.toString();
}
}
Unfortunately your approach isn't going to change anything. In fact, it introduces an additional object instantiation/allocation (your Concatenator). You're also using StringBuffer which introduces synchronization overhead you don't need.
The problem is the method signature for SLF4J's Logger.debug() calls. The first argument is always a String. This means you're going to have to call:
logger.debug(new Concatenator("Entering loop, arg is: ", arg).toString());
which means ... you're doing exactly the same thing as Java is going to do, but with more overhead.
The Java compiler handles the String concatenation operator (+) by creating a StringBuilder and doing exactly what you're doing in your Concatenator class on toString().
logger.debug("Entering loop, arg is: " + arg);
becomes:
logger.debug(new StringBuilder()
.append("Entering loop, arg is: ")
.append(arg).toString());
(If you use javap to look at the generated bytecode, you'll see that's the case.)
So, your current approach is going to be more expensive than what you have now.
Edit: So, the way you could make this work is by doing ...
logger.debug("{}", new Concatenator("Entering loop, arg is: ", arg));
This way your Concatenator is passed as an Object and its toString() not called unless the logger needs to. Also, replace the StringBuffer in your class with StringBuilder.
And if I didn't answer your question directly ... is this better than the original? Probably; The string concatenation isn't occurring unless it needs to. You are, however, introducing an object instantiation/allocation. The only real way to see the differences would be to profile it / write a benchmark.

Categories