So I developing this very simple game of TicTacToe. I want to test the method given below:
public class Board {
private Scanner scan = new Scanner(System.in);
public int inputBoardSize() {
while (flag) {
System.out.print("Enter the number of grids you want to play with:");
try {
boardSize = Integer.parseInt(scan.next());
if (boardSize < 3 || boardSize > 10) {
System.out.println("Please choose a board size between 3 and 10");
continue;
}
flag = false;
break;
} catch (NumberFormatException e) {
e.getMessage();
System.out.println("Please enter a number");
continue;
}
}
printBoard(boardSize);
return boardSize;
}
But I am new to unit testing and need a little help. I am not able to figure out how to test two conditions
the NumberFormatException
When the input is not between 3 and 10.
My testing class for the second condition is something like this:
public class BoardTest extends TestCase {
#Test
public void test() {
Board board = new Board();
String input = "2";
InputStream in = new ByteArrayInputStream(input.getBytes());
System.setIn(in);
}
}
I am not able to figure out what to do next.
You can extract the validation logic into a separate method and then test that method. This removes the need to interact or inject a Scanner object. The extracted code would resemble
public int inputBoardSize() {
while (flag) {
System.out.print("Enter the number of grids you want to play with:");
validateBoardSize(scan.next());
}
printBoard(boardSize);
return boardSize;
}
protected void validateBoardSize(String input) {
try {
boardSize = Integer.parseInt(input);
if (boardSize < 3 || boardSize > 10) {
System.out.println("Please choose a board size between 3 and 10");
}
else {
flag = false;
}
}
catch (NumberFormatException e) {
e.getMessage();
System.out.println("Please enter a number");
}
}
Some JUnit test cases to exercise the validateBoardSize method would be:
public class BoardTest {
private static final String OUT_OUT_BOUNDS_ERROR_MESSAGE = "Please choose a board size between 3 and 10";
private static final String NFE_ERROR_MESSAGE = "Please enter a number";
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private Board board;
#Before
public void setUp() {
System.setOut(new PrintStream(outContent));
board = new Board();
}
#Test
public void setBoardSizeOf2EnsureErrorMessageDisplayed() {
board.validateBoardSize("2");
assertOutOfBoundsErrorMessageDisplayed();
}
private void assertOutOfBoundsErrorMessageDisplayed() {
assertEquals(OUT_OUT_BOUNDS_ERROR_MESSAGE, outContent.toString().trim());
}
#Test
public void setBoardSizeOf3EnsureNoErrorMessageDisplayed() {
board.validateBoardSize("3");
assertNoErrorMessageDisplayed();
}
private void assertNoErrorMessageDisplayed() {
assertEquals("", outContent.toString().trim());
}
#Test
public void setBoardSizeOf4EnsureNoErrorMessageDisplayed() {
board.validateBoardSize("4");
assertNoErrorMessageDisplayed();
}
#Test
public void setBoardSizeOf9EnsureNoErrorMessageDisplayed() {
board.validateBoardSize("9");
assertNoErrorMessageDisplayed();
}
#Test
public void setBoardSizeOf10EnsureNoErrorMessageDisplayed() {
board.validateBoardSize("10");
assertNoErrorMessageDisplayed();
}
#Test
public void setBoardSizeOf11EnsureErrorMessageDisplayed() {
board.validateBoardSize("11");
assertOutOfBoundsErrorMessageDisplayed();
}
#Test
public void setBoardSizeWithInvalidNumberEnsureInvalidNumberMessageDisplayed() {
board.validateBoardSize("blah");
assertInvalidNumberMessageDisplayed();
}
private void assertInvalidNumberMessageDisplayed() {
assertEquals(NFE_ERROR_MESSAGE, outContent.toString().trim());
}
}
Note that since your program denotes errors through messages sent through standard output (as opposed to throwing exceptions), the tests must intercept the output message sent to standard output and do a string compare to see what the message says. Hence, within setUp(), the OutputStream for standard output is set to an OutputStream instance whose string value can be compared against by the test methods: System.setOut(new PrintStream(outContent)). To test the output, you can just extract the string value of the OutputStream: outContent.toString().trim(). Note that trim() is used to remove the trailing newline character(s), since println will include them in the error message. Newlines are OS-sensitive, so removing them makes comparing the string much more straightforward.
For more information, see JUnit test for System.out.println().
Add the following constructors:
public class Board {
private Scanner;
public Board() {
this(System.in);
}
public Board(InputStream in) {
scan = new Scanner(in);
}
}
Then you can provide provide an InputStream from the outside when testing the class.
Related
Perhaps my title is not very clear, but I try to understand this problem.
Problem: I have many assignments and different persons solve them using their own way. They may need input from user process it and do what they want, I want to individually run their solutions as well as in a framework which run all solutions in one go. Below is the overall simplistic approach I designed as a framework.
But as this code straight showing me that I will get NoSuchElementException (using Scanner) StreamClosed (using BufferedReader) approach.
How can I achieve this or am I thinking very wrong or missing any core concepts?
I don't want a scanner in main and pass its instance to all my code,( is this the only approach I can solve it)
public class AssignmentRunner {
public static void main(String[] args) {
AssignmentRunner runner = new AssignmentRunner();
AssignmentExecutor executor = new AssignmentExecutor();
executor.execute();
}
}
public interface Assignment {
void execute();
}
class AssignmentExecutor {
public List<Assignment> assignmentList ;
private void addAssignments(){
assignmentList = new ArrayList<Assignment>();
assignmentList.add(new Assignment1());
assignmentList.add(new Assignment2());
}
public void execute() {
addAssignments();
for (Assignment assigment : assignmentList) {
assigment.execute();
}
}
}
public class Assignment1 implements Assignment {
String inputString;
#Override
public void execute() {
input();
System.out.println(inputString);
}
private void input() {
Scanner scanner = new Scanner(System.in);
try {
inputString = scanner.nextLine();
}
catch (Exception e) {
System.err.println(e.getMessage());
}
finally {
scanner.close();
}
}
}
public class Assignment2 implements Assignment {
String inputString;
#Override
public void execute() {
input();
System.out.println("Hello"+inputString);
}
private void input() {
Scanner scanner = new Scanner(System.in);
try {
inputString = scanner.nextLine();
}
catch (Exception e) {
System.err.println(e.getMessage());
}
finally {
scanner.close();
}
}
}
EDIT: As per some comments and one answer I have made few modifications,kindly help me to understand is this the only best thing we can do or any other way to design my need.
NEED Different students can have different assignments for example (some may need input,others may not need any input)
simply print hello world
input string and show word count
input number show factorial
input number print its table
We want to execute each assignment class individually as well as from one Runner class as shown above.
MODIFICATION I did these modifications to all classes, showing sample for understanding what I did.
class AssignmentExecutor {
public List<Assignment> assignmentList ;
private void addAssignments(){
assignmentList = new ArrayList<Assignment>();
assignmentList.add(new Assignment1());
assignmentList.add(new Assignment2());
}
public void execute() {
Scanner scanner = new Scanner(System.in);
addAssignments();
for (Assignment assigment : assignmentList) {
assigment.execute(scanner);
}
scanner.close();
}
}
public class Assignment1 implements Assignment {
String inputString;
public static void main(String args[]) {
Assignment1 assignment1 =new Assignment1();
Scanner scanner = new Scanner(System.in);
assignment1.execute(scanner);
scanner.close();
}
#Override
public void execute(scanner) {
input(scanner);
System.out.println(inputString);
}
private void input(scanner) {
scanner = new Scanner(System.in);
try {
inputString = scanner.nextLine();
}
catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
So I'm trying to do a User class and then trying to do an array for it
however every time I create a student it don't add to the array.
I tried to change names etc but its really a problem in code.
public class UsersList {
User student;
User[] studentList = new User[49];
public UsersList() {
}
public void createUser(int userNumber) {
String numberToString = String.valueOf(userNumber);
if (numberToString.length() == 9) {
for (int i = 0; i < 49; i++) {
if (studentList[i] == null) {
studentList[i] = new User(userNumber);
}
}
}
}
}
public class User {
public int userNumber;
private boolean isolation;
private String state;
public User(int number) {
userNumber = number;
isolation = false;
}
}
If someone can help me I would be greatful.
I added the following simple test method to UsersList class to demonstrate that the code is fine and you need to provide appropriate userNumber value when calling createUser method:
public static void main(String[] args) {
UsersList list = new UsersList();
int userNumber = 1;
list.createUser(userNumber); // insufficient length
System.out.printf("all nulls for %d? %s%n", userNumber, Arrays.stream(list.studentList).filter(Objects::isNull).count() == list.studentList.length);
userNumber = 123_456_789;
list.createUser(userNumber); // length of the number is 9
System.out.printf("no nulls for %d? %s%n", userNumber, Arrays.stream(list.studentList).filter(Objects::nonNull).count() == list.studentList.length);
}
Output:
all nulls for 1? true
no nulls for 123456789? true
However, you may want also to initialize the instance variable student.
I am having diffculty with trying to assign value to array elements based on a userinput and checking the array element's value in another class. When I do that I get null and I am not sure why and how to fix it.
I have no expereince with java, just started learning it and doing it as part of uni course.
Any help is appreciated and thank you.
Class 1
public class ErrorHandling {
String[] errorMessage = new String[4];
public void inputCheck() {
UserInterface input = new UserInterface();
int[] checkUserInput = input.getInput();
if (checkUserInput[0] < 20 || checkUserInput[0] > 80) {
errorMessage[0] = "Hello";
}
if (!(checkUserInput[1] <= 10 && checkUserInput[1] % 2 == 0)) {
errorMessage[2] = "Hey";
}
}
public String[] getError() {
return errorMessage;
}
}
Class 2
public class MainProgram {
public static void main(String[] args) {
UserInterface input = new UserInterface();
input.askZigZag();
ErrorHandling checkError = new ErrorHandling();
String check[] = checkError.getError();
if (check[0] == ("Hello")) {
System.out.println("yh");
}
}
}
I think you're confusing your method calls a bit. In class 2, you have a line:
String check[] = input.getError();
That should probably be:
String check[] = checkError.getError();
As the getError() method is in your first class (ErrorHandling) and not the UserInterface class.
Also, you assign Hello to errorMessage[0] and not hey, so that might be failing in your last few lines in class 2.
If you're just starting out with Java I recommend reading up on Class Structure to understand this (as well as Arrays).
**EDIT
String comparison in Java doesn't work using the == operator. As they are objects and not primitive data types, you must use .equals.
check[0].equals("Hello")
Invoke checkError.inputCheck() in the main program otherwise errorMessage will not get initialized.
Some tweaks in your code that will help to execute:
Class 1
public class ErrorHandling {
String[] errorMessage = new String[4];
public void inputCheck() {
UserInterface input = new UserInterface();
int[] checkUserInput = input.getInput();
// If you want to use askZigZag... use it somewhere inside this function
// since you have already declared the object of UserInterface.
if (checkUserInput[0] < 20 || checkUserInput[0] > 80) {
errorMessage[0] = "Hello";
}
if (!(checkUserInput[1] <= 10 && checkUserInput[1] % 2 == 0)) {
errorMessage[2] = "Hey";
}
}
public String[] getError() {
return errorMessage;
}
}
Class 2
public class MainProgram {
public static void main(String[] args) {
// UserInterface input = new UserInterface();
// input.askZigZag();
ErrorHandling checkError = new ErrorHandling();
checkError.inputCheck();
String check[] = checkError.getError();
if (check[0].equals("Hello")) {
System.out.println("yh");
}
}
}
I'm making an application that quizzes you on politics or astronomy.
My problem is that when you say "politics" or you say "astronomy", it will ask you again 2 more times for your input, before giving the desired output of "test".
Here's the code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
do {
if (getAnswer().equalsIgnoreCase("neither")) {
System.out.println("Please enter \'astronomy\' or \'politics\'.");
}
getAnswer();
}
while(getAnswer().equalsIgnoreCase("neither"));
System.out.println("test");
}
public static String getAnswer() {
Scanner quizType = new Scanner(System.in);
System.out.println("Would you like to be quizzed on politics or astronomy?");
String typeAnswer = quizType.next();
if (typeAnswer.equalsIgnoreCase("politics")) {
return "politics";
}
else if (typeAnswer.equalsIgnoreCase("astronomy")) {
return "astronomy";
}
else {
return "neither";
}
}
}
Any ideas?
Thanks
There no need to getAnswer() 3 times, just getAnswer() into a String variable and you are good to go.
Like this:
public static void main(String[] args) {
String answer = "";
do {
answer = getAnswer();
if (answer.equalsIgnoreCase("neither")) {
System.out.println("Please enter \'astronomy\' or \'politics\'.");
}
} while (answer.equalsIgnoreCase("neither"));
System.out.println("test");
}
public static String getAnswer() {
Scanner quizType = new Scanner(System.in);
System.out.println("Would you like to be quizzed on politics or astronomy?");
String typeAnswer = quizType.next();
if (typeAnswer.equalsIgnoreCase("politics")) {
return "politics";
} else if (typeAnswer.equalsIgnoreCase("astronomy")) {
return "astronomy";
} else {
return "neither";
}
}
If you're learning do-while, then you only need to prompt inside your do. Currently you're calling getAnswer three times, which forces the repeated prompt.
Here is a quick way to solve it using do-while
public static void main(String[] args) {
List<String> validAnswers = Arrays.asList("neither","politics","astronomy");
String answer;
do {
answer = promptForAnswer();
} while(!validAnswers.contains(answer));
System.out.println("test");
}
public static String promptForAnswer() {
System.out.println("Would you like to be quizzed on politics or astronomy?");
return new Scanner(System.in).next();
}
Or you can go with the while loop...
public static void main(String[] args) {
List<String> validAnswers = Arrays.asList("neither","politics","astronomy");
while(!validAnswers.contains(promptForAnswer())) {
System.out.println("That was not a valid response, try again!");
}
System.out.println("test");
}
public static String promptForAnswer() {
System.out.println("Would you like to be quizzed on politics or astronomy?");
return new Scanner(System.in).next();
}
I need to know how to fetch the input for the operator for this simple program I am making that does this; the person enters a number, and if it's greater than 10, it displays the message "it worked". Where it says "NEED INPUT" is where I need the system scanner entry to go.
Operators class:
class Classes {
private int Numbers;
public Classes() {}
Classes(String namez) {
Numbers = Numbers;
}
public int getNumbers() {
return Numbers;
}
public void setNumbers(int numberz) {
if((Integer.parseInt(INPUT HERE.getText().toString()) )<=10) {
System.out.print("It worked.");
}
}
}
Main class:
import java.util.Scanner;
public class OneTwoThree {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter a number: ");
Classes.Numbers(keyboard.nextLine());
}
}
package mavens.dais.test;
public class ClassesTest {
private int Numbers;
public ClassesTest() {}
ClassesTest(String namez) {
Numbers = Integer.parseInt(namez);
}
public int getNumbers() {
return Numbers;
}
public void setNumbers(int numberz) {
if(numberz > 10){
System.out.print("It is worked.");
}else{
System.out.print("It is not worked.");
}
}
}
package mavens.dais.test;
import java.util.Scanner;
public class OneTwoThre {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter a number: ");
new ClassesTest().setNumbers(Integer.parseInt(keyboard.nextLine()));
}
}
Firstly
Classes.Numbers(keyboard.nextLine());
this should be replaced by Classes(keyboard.nextLine()); to begin with, in your class named OneTwoThree
Secondly
Classes(String namez) {
Numbers = Numbers;
}
this seems pretty much wrong.
Should be replaced by something like
Classes(String namez) {
Numbers = Integer.parseInt(namez); //if you are entering integers only through keyboard
}
As far as I could understand your question,
you can go like this then,
Classes(String namez) {
Numbers = Integer.parseInt(namez); //if you are entering integers only through keyboard
performOperation(Numbers);// call a method you want,pass number as arg
}
public static void performOperation(int num){
if(Numbers >10){
//do stuff
}
else{
//else part
}
}
}
Also ,just as a good practice you should name your variable Numbers to number.
I Hope it helped.
You just need to pass the String.
public static void testScanner() {
try (Scanner keyboard = new Scanner(System.in);) {
System.out.print("Enter a number: ");
while (true) {
String input = keyboard.nextLine();
if (input.equalsIgnoreCase("exit")) {
break;
}
Handler.handleInput(input);
}
System.out.println("Done.");
}
}
static class Handler {
public Handler() {
}
public static void handleInput(String input) {
try {
int x = Integer.parseInt(input);
if (x <= 10) {
System.out.println("It worked!");
} else {
System.out.println("Aw, Id didn't work.");
}
} catch (Exception ex) {
System.out.println("Hey, watch it buddy. Don't throw any letters in there, I don't like them.");
}
}
}