问题
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);
}
回答1:
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");
回答2:
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.
来源:https://stackoverflow.com/questions/34139658/how-to-junit-test-a-method-with-a-scanner