Advanced Java autograding

Discover the advanced autograding options available for Java assignments

In this guide, we explore the advanced grading options available for Java assignments. For more information about setting up a Java assignment from scratch, see

Create your first Java assignment

JUnit5

Junit5 is an industry-standard unit testing framework for Java. It is particularly useful for grading assignments that require students to write functions and classes. Using Junit5 unit tests offers several advantages over conventional IO tests including the ability to use assertions, parametrize test cases, and provide better feedback for students. Consider the example submission below:

Calculator.java
import java.util.Scanner;
public class Calculator {

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    System.out.print("Select operator: ");
    String operator = sc.nextLine();
    System.out.print("Enter two numbers: ");
    int num1 = sc.nextInt();
    int num2 = sc.nextInt();

    if (operator.equals("add")) {
        add(num1, num2);
    } else if (operator.equals("subtract")) {
        subtract(num1, num2);
    } else if (operator.equals("multiply")) {
        multiply(num1, num2);
    } else if(operator.equals("divide")) {
        divide(num1, num2);
    } else {
      System.out.println("The method you entered doesn't exist");
    }
  }

  public static float add(float numberOne, float numberTwo) {
    System.out.println(numberOne + numberTwo);
    return numberOne + numberTwo;
  }

  public static float subtract(float numberOne, float numberTwo) {
    System.out.println(numberOne - numberTwo);
    return numberOne - numberTwo;
  }

  public static float multiply(float numberOne, float numberTwo) {
    System.out.println(numberOne * numberTwo);
    return numberOne * numberTwo;
  }

  public static float divide(int numberOne, int numberTwo) {
    System.out.println(numberOne / numberTwo);
    return numberOne / numberTwo; // Should return ArithmeticException
  }
}

We can create robust test cases to check this submission using Junit5 assertions. Additionally, we can use decorators such as @displayName to make our test cases more readable and to increase the weight of individual test cases.

TestCalculator.java
import java.util.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
public class TestCalculator {
  @Test
  @DisplayName("Check whether the addition function returns the expected result.")
  public void test_add() {
    Assertions.assertEquals( 5, Calculator.add(2, 3), 0.2);
    Assertions.assertEquals( 0, Calculator.add(1, -1), 0.2);
    Assertions.assertEquals(-2, Calculator.add(-1, -1), 0.2);
  }
  @Test
  @DisplayName("Check whether the subtraction function returns the expected result")
  public void test_subtract() {
    Assertions.assertEquals( 3, Calculator.subtract(5, 2), 0.2);
    Assertions.assertEquals( 2, Calculator.subtract(1, -1), 0.2);
    Assertions.assertEquals( 0, Calculator.subtract(-1, -1), 0.2);
  }
  @Test
  @DisplayName("Check whether the multiply function returns the expected result")
  public void test_multiply() {
    Assertions.assertEquals( 6, Calculator.multiply(2, 3), 0.2);
    Assertions.assertEquals(-1, Calculator.multiply(1, -1), 0.2);
    Assertions.assertEquals( 1, Calculator.multiply(-1, -1), 0.2);
  }
  @Test
  @DisplayName("[2] Check whether the divide function returns the expected result and throws an ArithmeticException when dividing by 0 (weight 2)")
  public void test_divide() {
    Assertions.assertEquals( 5, Calculator.divide(10, 2), 0.2);
    Assertions.assertEquals(-1, Calculator.divide(1, -1), 0.2);
    Assertions.assertEquals( 1, Calculator.divide(-1, -1), 0.2);
    Assertions.assertThrows(ArithmeticException.class, () -> {
      Calculator.divide(10, 0);
    });
  }
}

"cg junit5" command

To make running JUnit5 tests in CodeGrade simpler, we created the cg junit5 command. This can be used to install JUnit5, automatically compile and run your JUnit5 test cases, or fetch the JUnit5 Jar files to run JUnit5 with your own custom specifications.

Running the command cg junit5 --help shows the following information:

A utility to install and run JUnit 5 in ATv2

Usage:
  cg junit5 [flags]
  cg junit5 [command]

Available Commands:
  get-classpath Returns the classpath necessary for running JUnit 5.
  get-jar       Returns the file path to the JUnit 5 runnable JAR if already installed.
  install       An installer for JUnit 5
  run           A reporter for JUnit 5 that directly runs it.

Flags:
  -h, --help   help for junit5

Use "cg junit5 [command] --help" for more information about a command.

The cg junit5 command works in combination with the Custom Test block by parsing the output of the JUnit5 test. The Custom Test block then renders the test results beautifully and makes it easy to read and interpret, as shown in the image below.

Instructions

  1. In the AutoTest settings, navigate to the Tests tab.

  2. Add an Upload Files block to your AutoTest configuration and upload your JUnit5 test files (eg. TestCalculator.java).

  3. Add an Allow Internet block and a Script block to your AutoTest configuration. Nest the Script block within the Allow Internet block. Download and install JUnit5 using the following command.

    cg junit5 install 1.10.0
  4. Add a Connect Rubric Block and a Custom Test block to your AutoTest configuration. Nest the Custom Test block within the Connect rubric block. Run the JUnit5 tests using the following command, using your Junit5 test file (eg. TestCalculator.java).

    cg junit5 run $FIXTURES/TestCalculator.java
  5. Build and publish your snapshot

JUnit5 has the known issue that it isn't possible to specify the order in which test cases are run. As a result, the results for each test case may displayed in a seemingly random order.

Checkstyle

Checkstyle is an industry-standard linter for Java that allows you to enforce rules from various style guides, including the Sun and Google style guides. It is a useful tool for enforcing code styling best practices for beginner programmers.

The Checkstyle block is an off-the-shelf testing tool that doesn't require any additional setup or configuration other than providing the name of the file to be tested. The Checkstyle block generates comments directly on students' code. Each target line is highlighted according to the severity of the comment and the comment can be read by hovering over the line number with the mouse cursor. The Checkstyle block also works in the built-in editor making it a powerful combination for beginners.

Although no setup is required, you can select from three readily available style guides: Checkstyle's default style guide, Sun style guide, and Google style guide. In addition, you can also update the configuration for each of these options to ignore or include any of the rules. Aside from style guides, you can also adjust the percentage of points deducted for each comment placed on a submission depending on its severity.

Conclusion

These advanced Java testing options open the door to more rigorous testing methods and better student feedback. However, these are just the most commonly used methods. There are many more testing tools and packages available that you can use with some simple setup. For more information, contact us at support@codegrade.com.

Last updated