An annotation library used to help autograde student assignments in Java for Gradescope.
Explore the docs »
Report Bug
·
Request Feature
This is an update to the original jGrade, now supporting Java17 and JUnit5. This provides four
annotations: @Grade
(+ @BeforeGrading
and @AfterGrading
) and @GradedTest
, each meant to help autograde
student assignments in Java for the Gradescope autograder. When correctly setup, instructors can
simply use JUnit5 to write tests for assignemnts. This library will automatically capture results,
and output the correct json format for Gradescope to read.
jGrade2 requires Java 17 and JUnit5. It is recommended to use Maven to manage dependencies. Additional
dependencies are listed in the pom.xml
file. For the user's convenience, a jar
file is provided
containing all the dependencies.
There are two ways to install jGrade2.
jar
files or build the source code from scratch. If building from source, this project uses
maven wrapper to build. Simply run ./mvnw clean package
to build the project. Two jar files will be
created, both reflected on the releases page.<dependency>
<groupId>io.github.dscpsyl</groupId>
<artifactId>jgrade2</artifactId>
<version>${jGrade2.version}</version>
</dependency>
Usage is nearly identical to the origional jGrade. jGrade2 comes with a commandline to run the grader manually. This is useful for debugging and testing. After compiling, you can use
java -jar jGrade2.jar -h
for help and options of the commandline. However, a typical usage would be
java -jar jGrade2.jar -c ExampleGrading -o results.json
You can take a look at the gradescope example in examples/gradescope
for a full example.
Tests are written in jUnit5. The only addition will be the @GradedTest
annotation to each test that should be counted in the
assignment on gradescope.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import com.github.dscpsyl.jgrade2.gradedtest.GradedTest;
import static com.github.dscpsyl.jgrade2.gradedtest.HIDDEN;
import static com.github.dscpsyl.jgrade2.gradedtest.VISIBLE;
public class ExampleTest {
@Test
@GradedTest(name="Example Test", points=10)
public void testExample() {
Assertions.assertTrue(true);
}
@Test
@GradedTest(name="Hidden Test", points=10, visibility=HIDDEN)
public void testHidden() {
Assertions.assertTrue(true);
}
@Test
@GradedTest(name="Visible Test", number="4", points=10, visibility=VISIBLE)
public void testVisible() {
Assertions.assertTrue(true);
}
}
The @GradedTest
annotation has the following parameters:
name
- The name of the test. This will be displayed in the Gradescope interface. DEFAUT: "Unnamed test"number
- The test number in a string. This will be displayed in the Gradescope interface. DEFAULT: ""points
- The number of points this test is worth. DEFAULT: 1.0visibility
- The visibility of the test. This can be either VISIBLE or HIDDEN. DEFAULT: VISIBLEGrading is done by a simple grading class. This class should be in the same package as the tests. Each method in the grading class
that should be considered for grading needs to be annotated with @Grade
. The method should take in a single parameter of type
Grader
. @BeforeGrading
and AfterGrading
can be used to run code before and after grading respectively. These methods should
also take in a single parameter of type Grader
.
import com.github.dscpsyl.jgrade2.Grader;
import com.github.dscpsyl.jgrade2.GradedTestResult;
import com.github.dscpsyl.jgrade2.Grade;
import com.github.dscpsyl.jgrade2.AfterGrading;
import com.github.dscpsyl.jgrade2.BeforeGrading;
import static com.github.dscpsyl.jgrade2.gradedtest.HIDDEN;
public class ExampleGrading {
/* This function will run before grading starts*/
@BeforeGrading
public void beforeGrading(Grader g) {
System.out.println("Starting grading");
grader.startTimer();
}
/* You can grade a full test class that is in the same package as this class */
@Grade
public void gradeTestClass(Grader g) {
g.runJUnitGradedTests(ExampleTest.class);
}
/* If you cannot use jUnit5 or java to grade, you can manually add results */
@Grade
public void gradeManually(Grader g) {
g.addGradedTestResult(new GradedTestResult("Manual Test", "4" , 10.0, HIDDEN));
}
/* Grader.startTimer() and Grader.stopTimer() can be used to time the grader */
@Grade
public void loopForTime(Grader grader) {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < 1000);
}
/* @AfterGrading methods are run after all other methods. */
@AfterGrading
public void endGrader(Grader grader) {
grader.stopTimer();
System.out.println("Grading finished");
}
}
There is a full example in examples/gradescope
that works on gradescope, and models much of the setup from the original java example Gradescope links to.
It compiles all files in to a created classes/
directory (not tracked). All the scripts will be looking for your classes in this directory.
The lib/
folder contains all jars and library files needed to run your test - for this example just the jGrade2 jar file (optionally a checkstyle jar for the checkstyle grading method). The res/
directory is for resources (like the checkstyle configuration file).
src/
is the main source code of both your grading code and your tests.
test_submissions/
are submissions to test with on Gradescope. These are precompiled for you to test with the grader that is included in the example.
The source has 2 main packages, staff
and student
. The staff package contains the unit tests, a solution (to debug with) and the code to do the grading. The student package contains studnet skeleton code for studnets to fill in.
While debugging, a makefile is provided for compiling and running. make output
will start fresh and run the autograder, pretty-printing the output to the console.
setup.sh
: Installs correct JDKrun_autograder
: Main script for the autograder. Copies in submission, compiles, and runs.compile.sh
: Compiles all of the source into a classes directoryrun.sh
: Runs JGrade, passing in the GradeHello
file, writing output
--local
then prints output to console, else to the results/results.json file.Either:
./mvnw clean package
to build the jGrade2 jarlib/
folder./make_autograder.sh
or make autograder
which will place it in the zips/
folder.Or:
./make_autograder_full.sh
which will complete the steps above for you, assuming the gradescope files are still in the examples
directory. This will put the final zip in the base directory instead of the zips/
folder. If you want to include checkstyle in the grading, please manually add the checkstyle jar to the lib/
folder before running this script.Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
The repository is structured like so:
main & master
The main branches for publishing to maven central. These should be kept clean and only update with releases. It is also protected and can only be added to via a pull request.dev
The development branch. This is where all development should be done and contains pe-releases. It is protected and can only be added to via a pull request.Other branches are for personal developnment and should only be pulled to the dev
branch. Once a release is determined, then a pull request can be made to main
or master
.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)Distributed under the MIT License. See LICENSE.txt
for more information.