JUnit test - how to check Scanner for various input mismatches - java

I'm trying to write JUnit tests for a program that converts Fahrenheit degrees to Celsius degrees (and opposite). So my class looks like:
package asdf;
import java.util.Scanner;
public class UnitTesting {
public UnitTesting()
{
}
public int returnInt()
{
Scanner scanner = new Scanner(System.in);
int x = scanner.nextInt();
return x;
}
public double returnDouble()
{
Scanner scanner = new Scanner(System.in);
double x = scanner.nextDouble();
return x;
}
public double convertCtoF(double c) {
return 1.8*c+32;
}
public double convertFtoC(double f) {
return (5.0/9.0*(f-32));
}
public void menu()
{
int a;
do {
System.out.println("1 - convert C degrees to F degrees");
System.out.println("2 - convert F degrees to C degrees");
System.out.println("0 - exit");
a = returnInt();
switch(a)
{
case 1:
System.out.println(convertCtoF(returnDouble()));
break;
case 2:
System.out.println(convertFtoC(returnDouble()));
break;
case 0:
System.out.println("Bye!");
break;
default:
System.out.println("Choose 1, 2 or 0");
break;
}
}
while(a!=0);
}
public static void main(String [] args)
{
UnitTesting ut = new UnitTesting();
ut.menu();
}
}
test class:
package asdf;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class UnitTestingTests {
private UnitTesting ut;
#BeforeEach
public void init() {
ut = new UnitTesting();
}
#Test
void checkIfInputMismatch() {
ut.returnDouble();
//some_kind_of_assert
}
}
Since I wanted to test the user input's for various mismatch exceptions (NumberFormat, InputMismatch etc.) but I have no idea if this approach is possible for current methods returnDouble() and returnInt(). I was thinking of changing scanner to read input as a string (nextLine) but then extra parsing method would be needed. What would be needed to alter the methods/class to check if input is a number at all, or has a good format given by the user - in an "elegant" way?
Thank you

Some common techniques include:
Separate user interaction and program logic (here temperature conversion) into separate classes. Unit test your logic alone. Very often one does not unit test the user interaction, but integration tests the entire program including user interaction (you may use JUnit or some other tool for this).
Don’t create a new Scanner every time you read input. Use the same Scaner throughout. In this case it won’t be too hard to inject a different Scanner that reads from some other source than System.in for test purposes (if you really insisted on creating a new Scanner you might have method that in production creates a Scanner that reads from System.in and in test creates one that reads from some other source; but as I said, don’t bother).
You may also set System.in to some other input stream than the keyboard for test purposes. And/or similarly rewire System.out to a different output stream that allows to test what is written to it.

To control the input is integer, double or an invalid input, you need to take input as string. Then you can use defined parse methods of wrapper classes.
package asdf;
import java.util.Scanner;
public class UnitTesting {
public int returnInt()
{
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
try{
int x = Integer.parseInt(s);
return x;
}catch(NumberFormatException ex){ // handle your exception, there you can give some messages to user.
System.out.println("The input is invalid for integer.");
}
}
public double returnDouble()
{
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
try{
double x = Integer.parseDouble(s);
return x;
}catch(NumberFormatException ex){ // handle your exception, there you can give some messages to user.
System.out.println("The input is invalid for double.");
}
}
public double convertCtoF(double c) {
return 1.8*c+32;
}
public double convertFtoC(double f) {
return (5.0/9.0*(f-32));
}
public void menu()
{
int a;
do {
System.out.println("1 - convert C degrees to F degrees");
System.out.println("2 - convert F degrees to C degrees");
System.out.println("0 - exit");
a = returnInt();
switch(a)
{
case 1:
System.out.println(convertCtoF(returnDouble()));
break;
case 2:
System.out.println(convertFtoC(returnDouble()));
break;
case 0:
System.out.println("Bye!");
break;
default:
System.out.println("Choose 1, 2 or 0");
break;
}
}
while(a!=0);
}
public static void main(String [] args)
{
UnitTesting ut = new UnitTesting();
ut.menu();
}
}
And the other way to control : Pattern matching
String input=...;
String pattern ="-?\\d+";
if(input.matches("-?\\d+")){ // any positive or negetive integer or not!
...
}

I created a library System Rules that provide rules for populating System.in and reading output from System.out. Your Test may look like this:
package asdf;
import static org.junit.Assert.*;
import org.junit.Test;
public class UnitTestingTests {
#Rule
public final TextFromStandardInputStream systemInMock
= emptyStandardInputStream();
private UnitTesting ut;
#Test
void checkIfInputMismatch() {
systemInMock.provideLines("1.23");
double value = ut.returnDouble();
//some_kind_of_assert
}
}
Unfortunately System Rules does only support JUnit 4. I'm working on a test framework independent alternative for System Rules.

Related

How to write a JUnit test for an atm validation program?

I'm new to java and I'm writing an ATM program where user can enter pin code three times and if they fail to enter the correct one, their card is blocked. I've tried to write a Junit test for the following code but I couldn't seem to figure it out. I have two classes AtmPin and AtmTester. AtmTester is where the main class is.
AtmPin.java
import java.util.Scanner;
public class AtmPin {
public static boolean validPIN(int user, int orignal){
return user==orignal;
}
public static int getPin(Scanner sc){
System.out.print("Enter PIN: ");
int pin = sc.nextInt();
return pin;
}
}
AtmTester.java
package atm;
import java.util.Scanner;
public class ATMTester {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int i = 0, userpin;
int PIN = 1234;
while(i< 3){
userpin = AtmPin.getPin(keyboard);
if(AtmPin.validPIN(userpin, PIN)){
System.out.println("Your PIN is correct");
System.exit(0);
}
else {
System.out.println("Your PIN is incorrect");
}
i++;
}
System.out.println("Your Bank Card is blocked");
}
}
Try to search the internet for "kata":
A "kata", or "coding kata", is defined as an exercise in programming which helps hone your skills through practice and repetition.
Searching for "kata atm" found this:
https://githubhelp.com/xpepper/ATM-kata-java
which may be a good starting point.
Each requerement of the kata can be translated to one or more junittests

Memory Calculator confusion java

In my class we needed to make a memory calculator in Java. Im really new to Java and had help making the program. Turned it in and the teacher said "Please separate the MemoryCalculator class from the class with the main() method. Currently the way you have created the class, there is no reason to create an instance of the class. But the point of the assignment is to use separate classes and objects." Its been a super long week and midterms and just lost at this time. Any help would be great.
import java.util.Scanner;
public class MemoryCalculator {
private double currentValue;
//Methods
//Scanner
public static int displayMenu(){
Scanner input = new Scanner(System.in);
System.out.print("Lets do some math! \nMenu \n1. Add \n2. Subtract \n3. Multiply \n4. Divide \n"
+ "5. Clear \n6. Quit \n\nWhat would you like to do? ");
int menuChoice = input.nextInt();
return menuChoice;
}
public static double getOperand(String prompt) {
Scanner input = new Scanner(System. in );
double operand;
System.out.println(prompt);
operand = input.nextDouble();
return operand;
}
//Current Value
//Gets
public double getCurrentValue() {
return currentValue;
}
//Setter
public void setCurrentValue(double currentValue) {
this.currentValue = currentValue;
}
//Add
public void add(double operand2) {
currentValue += operand2;
}
//Subtract
public void subtract(double operand2) {
currentValue -= operand2;
}
//Multiply
public void multiply(double operand2) {
currentValue *= operand2;
}
//Divide
public void divide(double operand2) {
if (operand2==0){
setCurrentValue(0);
}
currentValue /=operand2;
}
//Clear
public void clear() {
currentValue = 0;
}
//Main part of the calculator
public static void main(String[] args) {
MemoryCalculator instance = new MemoryCalculator();
double operand;
boolean repeat = true;
while (repeat) {
System.out.println("The current value is: " + instance.getCurrentValue() + "\n");
int menuChoice;
menuChoice = displayMenu();
if (menuChoice > 6 || menuChoice < 1){
System.out.println("I'm sorry, " + menuChoice + " wasn't one of the options\n");
}
switch(menuChoice){
case 1:
operand = getOperand("What is the second number?");
instance.add(operand);
break;
case 2:
operand = getOperand("What is the second number?");
instance.subtract(operand);
break;
case 3:
operand = getOperand("What is the second number?");
instance.multiply(operand);
break;
case 4:
operand = getOperand("What is the second number?");
instance.divide(operand);
break;
case 5:
instance.clear();
break;
case 6:
System.out.println("Goodbye have a great day");
System.exit(0);
break;
}
}
}
}
What it looks like you did with your program was create one, single, class that holds all of the code for your calculator program, within which you instantiated an object of the same class.
What your teacher wants instead, is for you to have two separate classes, one which contains the code that makes the calculator work, and another class where you instantiate an object of the first class, and call the methods contained within that class.
For your assignment, what I would suggest would be to create a new class, perhaps called Main, where your program's Main() method will be, and keep all of the code for the calculator program in the MemoryCalculator class. From there, you can instantiate an object of MemoryCalculator class (which you already did, called instance) and use method calls to reference methods and attributes from within the MemoryCalculator class.
This may require reworking some of your code so that it runs properly, given that you'll be calling most of it from an object of the MemoryCalculator class, but it should be doable.

How do I test out my program in the main method?

This will probably sound like a dumb question to many of you but I'm a new student and I am trying to learn. This is a program that takes a roman numeral input from a user and converts it to it's decimal value. I am trying to test out this program, but I don't know exactly what I have to do in my main method in order to do so. I have the other methods for the calculating but now how am I supposed to test it out? Let me show you what I have:
public class RomanNumeralConverter {
public String getUserInput() {
Scanner numberInput = new Scanner (System.in);
System.out.print("Enter a roman numeral in uppercase: ");
String userInput = numberInput.next();
numberInput.close();
return userInput;
}
public static void romanToDecimal(String userInput) {
int decimal = 0;
int lastNumber = 0;
userInput = userInput.toUpperCase();
for (int x = userInput.length() - 1; x >= 0 ; x--) {
char convertToDecimal = userInput.charAt(x);
switch (convertToDecimal) {
case 'M':
decimal = processDecimal(1000, lastNumber, decimal);
lastNumber = 1000;
break;
case 'D':
decimal = processDecimal(500, lastNumber, decimal);
lastNumber = 500;
break;
case 'C':
decimal = processDecimal(100, lastNumber, decimal);
lastNumber = 100;
break;
case 'L':
decimal = processDecimal(50, lastNumber, decimal);
lastNumber = 50;
break;
case 'X':
decimal = processDecimal(10, lastNumber, decimal);
lastNumber = 10;
break;
case 'V':
decimal = processDecimal(5, lastNumber, decimal);
lastNumber = 5;
break;
case 'I':
decimal = processDecimal(1, lastNumber, decimal);
lastNumber = 1;
break;
}
}
System.out.println(decimal);
}
public static int processDecimal(int decimal, int lastNumber, int lastDecimal) {
if (lastNumber > decimal) {
return lastDecimal - decimal;
} else {
return lastDecimal + decimal;
}
}
public static void main(String[] args) {
romanToDecimal(getUserInput);
}
}
You could see that I tried plugging in getUserInputin to romanToDecimal but I know that I don't have those parameters in the main method, and I don't even think Java allows me to do that. But, I think this represents what I'm trying to do. Really what I want to do is:
System.out.println("The number you entered is " + userInput
System.out.println("The converted number is " + romanToDecimal
Maybe I am supposed to put this in a separate method?
There are a few changes you need:
If you're going to call your getUserInput method from main, you either need to make it static or create an instance of your class. I'd suggest making it a static method.
Currently your romanToDecimal method prints out the result - but it would be neater (in my view) if instead it returned the result, so you can print it in main
In romanToDecimal(getUserInput) you're trying to use getUserInput as if it's a variable, but it's a method.
After changing getUserInput to be static, and changing romanToDecimal to return a String instead of printing it, your main method could look like this:
public static void main(String[] args) {
String input = getUserInput();
String result = romanToDecimal(input);
System.out.println("The number you entered is " + input);
System.out.println("The converted number is " + result);
}
That would be fine as a program. Once you've got romanToDecimal as a method returning the result, you could also easily write unit tests for it, where the input was hard-coded into the test, and you checked the result. For example:
public void test5() {
String result = RomanNumeralConverter.romanToDecimal("V");
Assert.assertEquals(5, result);
}
... and lots more tests for everything you can think of. (Depending on the unit test framework you choose, you might be able to write a single piece of test code, and specify the input and expected results very compactly as parameters.)
Do this in the main method:
String input = getUserInput();
romanToDecimal(input);
This should get the code working like it should.
Just write unit tests testing out the romanToDecimal method with various inputs.
In Java JUnit is the most popular framework for doing this.
The test would look something like this:
#Test
public void testMyMethod() {
assertEquals("expected result", romanToDecimal("input"));
}
PS: In order to do this successfully you will need to return a String in your romanToDecimal method!
try this:
public static void main(String[] args) {
RomanNumeralConverter rnc = new RomanNumeralConverter();
String userInput = rnc.getUserInput(); // get user input
System.out.println(userInput); // print user input
Tests.romanToDecimal(userInput); // call the romanToDecimal static method to convert and print converted decimal
}
getUserInput is a function name. getUserInput() is a call to the function, called getUserInput, passing no arguments to it (empty parenthesis). That's what you want: call that function, and use the string it returns.
romanToDecimal(getUserInput()); in your main function should work.
You can also assign it to a variable first, so that you could print it out before calling romanToDecimal, and also, make romatToDecimal return a String rather than just printing it out. Then you could do something like this:
public static void main(String argv[]) {
String input = getUserInput();
String output = romanToDecimal(input);
System.out.ptinln("You enetered: " + input + "\nThe converted number is: " + output);
}
Oh, and as someone has pointed out, you need to make both methods you are calling static.
If you put the userInput method into your main method then pass userInput to romanToDecimal(getUserInput); in the main method it will work here is the code for the main method
public static void main(String[] args) {
Scanner numberInput = new Scanner (System.in);
System.out.print("Enter a roman numeral in uppercase: ");
String userInput = numberInput.next();
numberInput.close();
romanToDecimal(userInput);`
}
}

user cannot add key to hashmap in java while loop

I am training myself in the use of hashmaps and thought it would be a good idea to build myself a financial planner program. I am trying to prompt user for a string key (bill name) and then apply that to a double value (also input by the user) which equates to the value of the bill. The result will be a hashmap with bill names (such as internet or electricity, for eg) and the values that those bills come to.
I have built a class called InputData - as follows:
package financial.planner;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class InputData {
private double salary;
private Map<String, Double> bills;
private boolean chooseContinue;
public InputData(){
super();
this.salary = 0.0;
this.bills = new HashMap<>();
this.chooseContinue = false;
}
//getters and setters for salary
public double getSalary(){
return this.salary;
}
public void setSalary(double aSalary){
this.salary = aSalary;
}
//getters and setters for bills
public Map<String, Double> getBills(){
return this.bills;
}
public void setBills(Map<String, Double> aBills){
this.bills = aBills;
}
//getters and setters for chooseContinue
public boolean getChooseContinue(){
return this.chooseContinue;
}
public void setChooseContinue(boolean aChooseContinue){
this.chooseContinue = aChooseContinue;
}
public void FPSalary(){
Scanner scanVar = new Scanner(System.in);
System.out.print("Enter salary: \n");
this.setSalary(scanVar.nextDouble());
}
public void FPBills(){
Scanner scanVar = new Scanner(System.in);
Map<String, Double> billsMap = new HashMap<>();
while(!this.getChooseContinue())
{
System.out.println("Enter bill name: \n");
String billName = scanVar.nextLine();
System.out.println("Enter bill value: \n");
double billValue = scanVar.nextDouble();
billsMap.put(billName, billValue);
this.FPChooseContinue();
}
this.setBills(billsMap);
setChooseContinue(false);
}
public void FPChooseContinue(){
Scanner scanVar = new Scanner(System.in);
System.out.println("Any more to add (y or n)?\n");
String yesOrNo = scanVar.nextLine();
switch (yesOrNo) {
case "y":
break;
case "n":
this.setChooseContinue(true);
break;
default:
System.out.print("Please enter y or n");
}
}
}
And in my main:
package financial.planner;
public class FinancialPlanner
{
public static void main(String[] args)
{
InputData IDobject = new InputData();
System.out.println("Financial Planner 1.0");
IDobject.FPSalary();
IDobject.FPBills();
System.out.println(IDobject.getBills());
}
}
The Program runs according to plan unless I try to add a second key (ie bill name) - it ignores this request and runs straight to the bill value instead:
Financial Planner 1.0 Enter salary: 30000 Enter bill name:
gas Enter bill value:
450 Any more to add (y or n)?
y Enter bill name:
Enter bill value:
37 Any more to add (y or n)?
n {=37.0, gas=450.0}
I'd very much appreciate an experienced programmer to lend me a hand on this one - Im probably doing something pretty dumb - but I love programming and want to get better! please help! Any other advice about my code would be also greatly appreciated.
According to the docs, nextLine() does the following:
Advances this scanner past the current line and returns the input that
was skipped. This method returns the rest of the current line,
excluding any line separator at the end.
A stray newline character must be causing the String billName = scanVar.nextLine (); to skip a line, since it's theoretically a line to be read.
You can use next() instead, which reads until the next input delimiter.
Try this you have interchanged the yes and no blocks
public void FPChooseContinue(){
Scanner scanVar = new Scanner(System.in);
System.out.println("Any more to add (y or n)?\n");
String yesOrNo = scanVar.nextLine();
switch (yesOrNo) {
case "y":
this.setChooseContinue(true);
break;
case "n":
break;
default:
System.out.print("Please enter y or n");
}
The nextDouble() method leaves the '\n' symbol which gets picked up immediately by nextLine(), skipping over the next input thus throwing an exception. What you want to do is use nextLine() for everything, and parse it later. So just replace
double billValue = scanVar.nextDouble();
WITH
double billValue = Double.parseDouble(scanVar.nextLine());

Multi Class program

Hi I was attempting to create a calculator that can add subtract multiply and divide to challenge myself but find myself getting stuck around the switch part:(I will point out the errors within the switch message that say "The method addition etc(String[]) in the type addition etc is not applicable for the arguments ()." I believe the problem lies within the public void of the other classes.
Script:
public class ComputronCalc {
public static void main(String args[]) {
int mode;
mode = 1;
Addition ADD = new Addition();
Subtraction SUB = new Subtraction();
Multiplication MUL = new Multiplication();
Division DIV = new Division();
System.out.println("Hello welcome to the Computron fully functional calculator, coded by Samuel Cole, designed by Dwight Schrute.");
switch(mode) {
case 1:
ADD.Addition();<-----------addition is underlined in red
break;
case 2:
SUB.Subtraction();<-------------same
break;
case 3:
MUL.Multiplication();<---------------same
break;
case 4:
DIV.Division();<----------------same
break;
default:
System.out.println("You have not selected a mode, do so by editing the mode variable in the source.");
}
System.out.println("Thank you for choosing Computron.");
}
}
import java.util.Scanner;
public class Addition {
public void Addition(String Args[]) {
Scanner input = new Scanner(System.in);
double fnum, snum, answer;
System.out.println("Type the first number you desire to calculate.");
fnum = input.nextDouble();
System.out.println("Type the second number you desire to calculate.");
snum = input.nextDouble();
System.out.println("Calculating...");
answer = fnum + snum;
System.out.println(answer);
}
}
import java.util.Scanner;
public class Multiplication {
public void Multiplication(String Args[]) {
Scanner input = new Scanner(System.in);
double fnum, snum, answer;
System.out.println("Type the first number you desire to calculate.");
fnum = input.nextDouble();
System.out.println("Type the second number you desire to calculate.");
snum = input.nextDouble();
System.out.println("Calculating...");
answer = fnum * snum;
System.out.println(answer);
}
}
import java.util.Scanner;
public class Division {
public void Division(String Args[]) {
Scanner input = new Scanner(System.in);
double fnum, snum, answer;
System.out.println("Type the first number you desire to calculate.");
fnum = input.nextDouble();
System.out.println("Type the second number you desire to calculate.");
snum = input.nextDouble();
System.out.println("Calculating...");
answer = fnum / snum;
System.out.println(answer);
}
}
note: I'm using eclipse so each class is on like a different page.
Your methods expect the argument "args", which you don't use. Remove it. For example:
public void Addition(String Args[]) {
becomes:
public void Addition() {
(by the way, your code does not follow Oracle Java Naming Convention)
While the acute problem is that you need to change your method signatures to not have any parameters or change the method invocation to send a parameter, I think there is a better solution you should concider.
Change the methods in your operation classes to be constructors:
public class Addition {
public Addition() {
//...
}
}
Then you do not need to instantiate all the operations for each run and the switch becomes:
switch(mode) {
case 1:
Addition();
break;
case 2:
Subtraction();
break;
case 3:
Multiplication();
break;
case 4:
Division();
break;
default:
System.out.println("You have not selected a mode, do so by editing the mode variable in the source.");
}
Do not have any parameter (in this program, the String[] args parameter) for the function inside the four operator classes. Your program should work without them.
public class Addition {
public Addition() {
//...
}
}
Same applies for other classes too.
public class Subtraction {
public Subtraction() {
//...
}
}
public class Multiplication{
public Multiplication() {
//...
}
}
public class Division {
public Division() {
//...
}
}

Categories

Resources