Reputation: 9
It is Question: Creating a program for a market. The system can send a family card to a consumer and accept a discount of 0% (no discount), 5%, or 10% based on the following rules:
If a registered user has spent more than $1000 on past food purchases and has less than 19 shopping sessions, they will receive a 5% discount.
If a registered user spent more than $1000 in prior grocery shopping sessions and had at least 20 grocery shopping sessions, they would receive a 10% discount.
Only registered users who spend over $1000 or have at least 20 shopping sessions receive a family card.
My codes below
package Market;
import java.util.Scanner;
public class Lab5
{
public static void main(String[] args)
{
int spent=0;
int market_sessions=0;
Scanner scan =new Scanner(System.in);
System.out.printf("Amount spent by customer: ");
spent=Integer.parseInt(scan.nextLine());
Scanner scan2 =new Scanner(System.in);
System.out.printf("Marketsessions by the customer: ");
market_sessions=Integer.parseInt(scan2.nextLine());
int a = 0;
int type=userType(a);
if(type==1)
{
int discount=discounts(spent, market_sessions);
System.out.println("Discount: "+discount);
if(spent>1000 || market_sessions>=20)
System.out.println("Family card is sent to the customer");
}
else
{
System.out.println("Family cards and discounts are not given to unregistered users.");
}
}
public static int discounts(int spent, int market_sessions)
{
int discount=0;
if(spent>1000)
{
if(market_sessions<=19)
discount=5;
else
discount=10;
}
return discount;
}
public static int userType(int a)
{
System.out.println("Enter 1 or 2");
System.out.println("1 = Registered User");
System.out.println("2 = Unregistered User");
Scanner scan3 =new Scanner(System.in);
a=Integer.parseInt(scan3.nextLine());
while(a<1 || a>2) {
System.out.println("Enter 1 or 2");
System.out.println("1 = Registered User");
System.out.println("2 = Unregistered User");
Scanner scan4 =new Scanner(System.in);
a=Integer.parseInt(scan4.nextLine());
}
return a;
}
}
My program works just fine. It satisfies the conditions in the question. But my problem is that no matter how hard I try, I can't run Junit tests. So, for example, I am writing the method, but I don't know how to test it. I tried a lot but I can't make the logic of your Junit test. Is there a problem with my program? Is Junit closed to testing my program? Because I'm getting numbers from the keyboard, is that it? Should I not use a scanner? Can you write a Junit test from my program?
Upvotes: 0
Views: 77
Reputation: 6549
Each unit test, as the "unit" in the name suggests, should focus on testing just a small part of your application (not the whole application).
The actual platform input and output (I/O) should not be part of a unit test. There are ways to mock I/O classes, so you could use a Scanner mock in tests, but even that would require some refactoring of your current code to be possible. But I don't think that should be your goal. I think your goal should be to write your code in such a way that it is easier to unit test without the need to mock the platform code, when possible.
The logic (domain logic, business logic, whatever logic you need in your application) should be confined in functions/methods. Ideally only the input of those functions should determine their output, i.e. ideally your functions should have no side effects (pure functions). Functions without side effects are a lot easier to test.
In your case the method public static int discounts(int spent, int market_sessions)
contains some of your application logic, and it has no side effects, so it would be a good candidate for a unit test.
The unit test would then look like this (using JUnit 5, it is a bit different API if you would like to use JUnit 4)
import Market.Lab5;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class Lab5Test {
@Test
public void registered_users_should_receive_a_discount_conditionally() {
assertEquals(0, Lab5.discounts(Integer.MIN_VALUE, Integer.MIN_VALUE));
assertEquals(0, Lab5.discounts(0, 0));
assertEquals(0, Lab5.discounts(1000, 18));
assertEquals(0, Lab5.discounts(1000, 19));
assertEquals(0, Lab5.discounts(1000, 20));
assertEquals(5, Lab5.discounts(1001, 18));
// if we follow the rules strictly this discount should be 0,
// but if we follow the common sense it should be 5
// ask for clarification of the rules (if it is a typo in the rules or not)
assertEquals(5, Lab5.discounts(1001, 19));
assertEquals(10, Lab5.discounts(1001, 20));
assertEquals(10, Lab5.discounts(Integer.MAX_VALUE, Integer.MAX_VALUE));
}
}
You have a bit more logic in the line if(spent>1000 || market_sessions>=20)
. So this line could be refactored into a new method, so that it can be put under a unit test.
public static boolean supplyAfamilyCard(int spent, int market_sessions) {
return spent>1000 || market_sessions>=20;
}
Then unit tests can be
import Market.Lab5;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class Lab5Test {
// ...
@Test
public void registered_users_should_receive_a_family_card_for_more_than_1000_spent() {
assertFalse(Lab5.supplyAfamilyCard(Integer.MIN_VALUE, 19));
assertFalse(Lab5.supplyAfamilyCard(0, 19));
assertFalse(Lab5.supplyAfamilyCard(1000, 19));
assertTrue(Lab5.supplyAfamilyCard(1001, 19));
assertTrue(Lab5.supplyAfamilyCard(Integer.MAX_VALUE, 19));
}
@Test
public void registered_users_should_receive_a_family_card_for_20_or_more_sessions() {
assertFalse(Lab5.supplyAfamilyCard(true, 1000, Integer.MIN_VALUE));
assertFalse(Lab5.supplyAfamilyCard(true, 1000, 0));
assertFalse(Lab5.supplyAfamilyCard(true, 1000, 19));
assertTrue(Lab5.supplyAfamilyCard(true, 1000, 20));
assertTrue(Lab5.supplyAfamilyCard(true, 1000, Integer.MAX_VALUE));
}
}
If not already, the org.junit.jupiter
(or a JUnit 4) library dependency has to be added to your project for the above imports to work. If you are using a Java IDE, each of them has a way of adding dependencies. If you are using a build system and are using repositories (such as Maven) you would add the org.junit.jupiter
(or JUnit 4 equivalent) in the build script as a dependency.
When running the tests, all tests pass (assuming that the discount for 19 sesssion when spending more than 1000 is 5 and not 0 as the rules would suggest)
Upvotes: 3