Java 2

Week 7

Topics Covered this week

  • Test Driven Development (TDD)
  • Exceptions, communicating messages between servlets and JSPs
  • Midterm Exam Review

FractionTest Class

  • In IntelliJ, right-click the Fraction class title and choose "Show Context Options" then "Create Test".

  • JUnit 5 will be pre-selected, because it is installed in pom.xml

  • Check the "setUp/@Before" box. Click the check boxes next to all of the methods.

  • The FractionTest class is successfully added to the tests folder.

  • Fully-qualified annotations ("@org.junit.jupiter.api.BeforeEach" and "@org.junit.jupiter.api.Test") only need to be @BeforeEach and @Test.

    • If your annotations are fully-qualified press Ctrl + R to open the find and replace menu.

    • Replace all references of "@org.junit.jupiter.api." with "@".

    • Add an import statement for @BeforeEach and @Test.

BeforeEach Methods

  • Some Unit Tests require a default instance of the class.

  • The setUp method can be used to instantiate that object needed for each test.

  • Create two new Fraction objects as a private instance variables.

  • Instantiate the Fraction objects in the setUp method.

  • We want to keep our code DRY (Don't Repeat Yourself). If we don't use the setUp method we will have to instantiate a Fraction object inside of every single test method.

private Fraction f1;
private Fraction f2;

@BeforeEach
void setUp() {
    f1 = new Fraction();
    f2 = new Fraction(2, 3);
}

Run the tests

  • Study the fail method from JUnit's Assertions class.

  • If you run the tests now, it should say all tests passed and you will see green checkmarks next to the method names in the bottom-left corner. We actually want all tests to fail by default.

  • Highlight a set of curly brackets on one of the tests.

    • Press Ctrl+Cmd+G (Mac) or Shift+Ctrl+Alt+J (Windows) to select all occurrences.

    • Use the arrow keys to position the cursors inside the curly brackets and type a fail method.
      fail();

      • This is a static method from the Assertions class of JUnit.

  • Run the FractionTest class again to see that all tests failed. You will see orange X's next to the method names.

Test the Getters and toString

  • Study the assertEquals methods from JUnit's Assertions class.

  • Write tests for all of the getters and toString.

    • You should test all getter methods before setter methods so you can safely use the getter methods to verify that the setter methods work correctly.

    • When using the assertEquals method the first argument is the expected value and the second argument is the actual value.

    • The actual value will always come from a getter method.

  • When you run the tests, 3 will pass, the rest will fail.

@Test
void getNumerator() {
    assertEquals(1, f1.getNumerator());
    assertEquals(2, f2.getNumerator());
}

@Test
void getDenominator() {
    assertEquals(1, f1.getDenominator());
    assertEquals(3, f2.getDenominator());
}

@Test
void testToString() {
    assertEquals("1/1", f1.toString());
    assertEquals("2/3", f2.toString());
}

Test the Setters

  • Next, we will write tests for all of the setters

  • For setNumerator, I am setting a positive, 0, and negative value. I am calling the getNumerator and toString methods to ensure equality.

  • For setDenominator, I am setting a positive, 0, and negative value. I am calling the getDenominator and toString methods to ensure equality.

  • Because the denominator cannot be 0, we use assertThrows. The lambda expression call's the Executable abstract method.

@Test
void setNumerator() {
    f1.setNumerator(3);
    assertEquals(3, f1.getNumerator());
    assertEquals("3/1", f1.toString());
    f1.setNumerator(0);
    assertEquals(0, f1.getNumerator());
    assertEquals("0/1", f1.toString());
    f1.setNumerator(-3);
    assertEquals(-3, f1.getNumerator());
    assertEquals("-3/1", f1.toString());
}

@Test
void setDenominator() {
    f1.setDenominator(3);
    assertEquals(3, f1.getDenominator());
    assertEquals("1/3", f1.toString());
    f1.setDenominator(-3);
    assertEquals(-3, f1.getDenominator());
    assertEquals("-1/3", f1.toString());
}

Test Exceptions

  • Because the denominator cannot be 0, we use assertThrows.

  • The first argument is the type of Exception you expect to be thrown, in this case ArithmeticException.

  • The second argument is a lambda expression that  call's the abstract method from the Executable functional interface.

  • assertThrows returns a Throwable object of type T, in this case ArithmeticException. You can assert the Exception message.

assertThrows(ArithmeticException.class, () -> f1.setDenominator(0));

ArithmeticException e = assertThrows(ArithmeticException.class, () -> f1.setDenominator(0));
assertEquals("cannot be zero", e.getMessage());

Test Static Methods

  • In the gcd test method, call the static gcd method from the Fraction class.
  • The following assertions seem logical, but they don't fully test it.

@Test
void gcd() {
    int result1 = Fraction.gcd(5, 7);
    int result2 = Fraction.gcd(-5, 7);
    int result3 = Fraction.gcd(5, -7);
    int result4 = Fraction.gcd(-5, -7);
    assertTrue(result1 == result2 && result2 == result3 && result3 == result4);
}
@Test
void gcd() {
    assertEquals(15, Fraction.gcd(75, 45));
    assertEquals(2, Fraction.gcd(2, 4));
    assertEquals(1, Fraction.gcd(5, 7));
}

Test simplify Method

  • Set the numerator to 75 and denominator to 45.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "5/3".
  • Set the numerator to 2 and denominator to 4.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "1/2".
  • Set the numerator to 5 and denominator to 7.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "5/7".
@Test
void simplify() {
    f1.setNumerator(75);
    f1.setDenominator(45);
    f2 = f1.simplify();
    assertEquals("5/3",f2.toString());

    f1.setNumerator(2);
    f1.setDenominator(4);
    f2 = f1.simplify();
    assertEquals("1/2",f2.toString());

    f1.setNumerator(5);
    f1.setDenominator(7);
    f2 = f1.simplify();
    assertEquals("5/7",f2.toString());
}

Test simplify Method

  • Set the numerator to -2 and denominator to 4.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "-1/2".
  • Set the numerator to 2 and denominator to -4.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "-1/2".
  • Set the numerator to -2 and denominator to -4.
    • Call the simplify method to return a new Fraction object.
    • The value returned should be "1/2".
@Test
void simplify() {
    f1.setNumerator(75);
    f1.setDenominator(45);
    f2 = f1.simplify();
    assertEquals("5/3",f2.toString());

    f1.setNumerator(2);
    f1.setDenominator(4);
    f2 = f1.simplify();
    assertEquals("1/2",f2.toString());

    f1.setNumerator(5);
    f1.setDenominator(7);
    f2 = f1.simplify();
    assertEquals("5/7",f2.toString());

    f1.setNumerator(-2);
    f1.setDenominator(4);
    f2 = f1.simplify();
    assertEquals("-1/2",f2.toString());

    f1.setNumerator(2);
    f1.setDenominator(-4);
    f2 = f1.simplify();
    assertEquals("-1/2",f2.toString());

    f1.setNumerator(-2);
    f1.setDenominator(-4);
    f2 = f1.simplify();
    assertEquals("1/2",f2.toString());
}

Test add Method

  • Call the add method to return a String representing the sum of adding two Fractions.
  • Set the numerator and denominator to different values
  • Call the add method again to return a different String represention.
@Test
void add() {
    assertEquals("1 + 2/3 = 1 2/3", f1.add(f2));

    f1.setNumerator(25);
    f1.setDenominator(-100);

    f2.setNumerator(-10);
    f2.setDenominator(-15);
    assertEquals("-1/4 + 2/3 = 5/12", f1.add(f2));
}

Midterm Exam Review

  • You must be physically present in class to take the midterm exam.

    • You cannot take the exam virtually.

Midterm Exam

  • You will randomly be assigned a CSV data set.

    • Read 3-4 fields from the CSV file to create a List of objects.

    • Get the objects with the highest/lowest value of an attribute.

    • Sort the List of objects by two attributes

  • You will randomly be assigned a conversion type.

    • Create a JSP to display a form that reads a single input and displays output.

    • Create a servlet that validates input and produces output.

      • Numbers cannot be negative

  • When finished, raise your hand and show the teacher your completed work.

Midterm Exam Review

  • Download the Covid-19 data set as tab-separated values (TSV) since some of the data contains commas.

  • Create a class called MidtermReview. 

  • Create a class called CovidData

  • Create a static List<CovidData>

import java.util.*;

public class MidtermPractice {
    private static List<CovidData> data = new ArrayList<>();
 
}

class CovidData {
    private String countyName;
    private String state;
    private int totalCases;

    public CovidData(String countyName, String state, int totalCases) {
        this.countyName = countyName;
        this.state = state;
        this.totalCases = totalCases;
    }

    public String getCountyName() {
        return countyName;
    }

    public void setCountyName(String countyName) {
        this.countyName = countyName;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public int getTotalCases() {
        return totalCases;
    }

    public void setTotalCases(int totalCases) {
        this.totalCases = totalCases;
    }

    @Override
    public String toString() {
        return "CovidData [countyName=" + countyName + ", state=" + state + ", totalCases="
                + totalCases + "]";
    }
    
    public static Comparator<CovidData> compareTotalCases = Comparator.comparing(CovidData::getTotalCases);

}

Midterm Exam Review

  • Write a main method

  • Call FileInput.readAllLines method.

  • Convert lines in the List<String> to CovidData objects

  • Print the county with the highest total cases

  • Sort the data highest to lowest.

public static void main(String[] args) {
  List<String> lines = FileInput.readAllLines("COVID-19.tsv");
  // lines.forEach(System.out::println);
  for(String line: lines) {
    try {
      String[] record = line.split("\t");
      String countyName = record[1];
      String state = record[2];
      int totalCases = Integer.parseInt(record[4]);
      data.add(new CovidData(countyName, state, totalCases));
    } catch(NumberFormatException e) {
    	continue;
  	}
  }
  // data.forEach(System.out::println);
  CovidData highest = data.stream().max(Comparator.comparing(CovidData::getTotalCases)).get();
  System.out.println(highest);
  Collections.sort(data, CovidData.compareTotalCases.reversed());
  for(int i = 0; i < 10 ; i++) {
  	System.out.println(data.get(i));
  }
}