Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to JUnit test a Method with a Scanner?

I have a class which reads a file and takes in a user input with a scanner and if the scanner equals a part of a line in that file, it will display a string from the same line.

How would I go and create a Junit test method for this?

Here is some of my code that I want a test method for:

Scanner Input = new Scanner(System.in);
    String name = Input.nextLine();

    BufferedReader br;
   try{
       br = new BufferedReader(new FileReader(new File(filename)));
       String nextLine;
       while ((nextLine = br.readLine()) != null)
       {
           if (nextLine.startsWith("||"))
           {
                int f1 = nextLine.indexOf("*");
                int f2 = nextLine.indexOf("_");
                fName = nextLine.substring(f1+1, f2);
                   if (name.equals(fname))
                   {
                        String[] s1 = nextLine.split("_");
                        String sName = s1[1];
                        System.out.println(sName);
                   }
           }
       }

my data file looks like this

||
*Jack_Davis
*Sophia_Harrolds

I have tried to use this code in my test method

@Test
public void testgetSurname() {
    System.out.println("get surname");
    String filename = "";
    String expResult = "";
    String result = fileReader.getSurname(filename);
    assertEquals(expResult, result);

    filename = "datafiles/names.txt";
    String data = "Jack";
    InputStream stdin = System.in;
    try{
      System.setIn(new ByteArrayInputStream(data.getBytes()));
      Scanner scanner = new Scanner(System.in);
      System.out.println(scanner.nextLine());
    } finally {
      System.setIn(stdin);
      expResult = "Davis";
    }
    String result = fileReader.getSurname(filename);
    assertEquals(expResult, result);                
}
like image 989
MarcusFenix1 Avatar asked Feb 08 '23 08:02

MarcusFenix1


2 Answers

try this for example:

You could enhance it by simulate the console automatically (see below)

@Test
public void test_scan() throws Exception
{
Myclass myobject=new myobject(); // with args

myobject.load(filename); // you must definie the filename

String result=myobject.scaninput_and_compare(); // you must use scan in, and compare

if (!result.equals(what_I_am_expecting) throw new Exception("EXCEPTION scaninput_and_compare"); 

// If you arrive here, it's OK
}

If you want to automatize the console input, use that:

Courtesy of: JUnit: How to simulate System.in testing?

String data = "What_I_could_put_in_console";
InputStream stdin = System.in;
System.setIn(new ByteArrayInputStream(data.getBytes()));
Scanner scanner = new Scanner(System.in);
System.setIn(stdin);

Beware of catch Exception inside, to finish with a "good" System.in It's ok for a test alone, for several, you should verify.

With your code:

public String scaninput_and_compare(String filename)
{
Scanner Input = new Scanner(System.in);
String name = Input.nextLine();

BufferedReader br;
 try{
   br = new BufferedReader(new FileReader(new File(filename)));
   String nextLine;
   while ((nextLine = br.readLine()) != null)
   {
       if (nextLine.startsWith("||"))
       {
            int f1 = nextLine.indexOf("*");
            int f2 = nextLine.indexOf("_");
            fName = nextLine.substring(f1+1, f2);
               if (name.equals(fname))
               {
                    String[] s1 = nextLine.split("_");
                    String sName = s1[1];
                    return sName;
               }
       }
   }
// NO GOOD
return "lose";
}


@Test
public void test_scan() throws Exception
{
Myclass myobject=new myobject(); // with args

String filename="good_filename";

// MOCK System.in
String data = "Jack";
InputStream stdin = System.in;
System.setIn(new ByteArrayInputStream(data.getBytes()));

String result=myobject.scaninput_and_compare(filename); // you must use scan in, and compare

// RESTABLISH System.in
Scanner scanner = new Scanner(System.in);
System.setIn(stdin);

if (!result.equals("Davis") throw new Exception("EXCEPTION scaninput_and_compare"); 

// If you arrive here, it's OK
}

BETTER design, and testing more easy: separate your scanner of System.in, from your file parsing. Just do a function with (filename, fname), and it will be direct to test :

assertEquals(myobject.scaninput_and_compare(filename,"Jack"), "Davis");
like image 141
guillaume girod-vitouchkina Avatar answered Feb 13 '23 23:02

guillaume girod-vitouchkina


One way to do it:

Step 1

Refactor your code, so that Scanner is one of the parameters passed into your method.

Step 2

For your test, use constructor Scanner(File file) or Scanner(String source) to feed "what would the user type" - while in the real world (from your main() you'd create Scanner(System.in)

or

Refactor your code to get a protected Scanner getScanner() { } and then use a Mocking framework (I like Mockito) to mock that method and return your String-prepped Scanner (see Step 2)

Requested example (the refactoring)

/**
* Reads the next line from the Scanner
*/
protected String getNextLine(Scanner scanner) {
  //You know how to do that.
}

/** 
*  Check if file contains that name and return matching line.
*  Throws NameNotFoundException (you'd need to create) if not found.
*
*  If it were my code, i'd refactor even more and pass in List<String> 
*  here with the lines from the file
*/
public String matchSurname(String name, File dataFile) throws NameNotFoundException {
   //Iterate over file... 
      if(isMatchingSurname(name, line)) {
        return line;
      }
   // end iteration
   //Still here? Throw Exception!
   throw new NameNotFoundException();
}

/**
* Checks if given Name matches the read line
*/
public boolean isMatchingSurname(String name, String lineFromFile) {
  //All the checks
}

Now you've broken your problem down in nice small bites. Unit testing would now be for individual methods only - so one for testing reading a line from Scanner, one for testing the Matching logic and one for correct file iteration.

like image 42
Jan Avatar answered Feb 13 '23 23:02

Jan