Welcome to repomate-junit4’s documentation!¶
Install¶
Requirements¶
Important
Once you have gone through this section, you should have:
- Repomate installed
- A JDK (preferably 8+, 7 may work) installed
junit-4.12.jar
andhamcest-core-1.3.jar
downloaded
First of all, make sure that Repomate is installed and up-to-date. For a first-time install of Repomate, see the Repomate install docs. If you already have Repomate installed, make sure it is up-to-date.
python3 -m pip install --user --upgrade repomate
Furthermore, a JDK must be installed. repomate-junit4
has been extensively
tested with OpenJDK 8+, but should work well with JDK 7 and later. Make sure
that:
java
is available from the command line.javac
is available from the command line.
To be able to actually run test classes, you also need the JUnit4 and Hamcrest jars. They can be downloaded from Maven Central.
wget http://central.maven.org/maven2/junit/junit/4.12/junit-4.12.jar
wget http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
If you don’t have wget
installed, just copy the links above and download
them manually.
Install plugin¶
To install repomate-junit4
, simply use pip
again.
python3 -m pip install --user repomate-junit4
Repomate should simply be able to find repomate-junit4
if they are both
installed in the same environment. To verify that it is correctly installed,
run repomate -p junit4 clone -h
. You should see some additional command
line arguments added (such as --reference-tests-dir
). See the Using
existing plugins for more information on how to use plugins in general,
and Usage for details on this plugin.
Configuration¶
Some options for repomate-junit4
can be configured in the Repomate
configuration file by adding the [junit4]
section. Everything
repomate-junit4
needs to operate can be provided on the command line, but
I strongly recommend adding the absolute paths to the junit-4.12.jar
and
hamcrest-core-1.3.jar
files to the config file. Simply append the following
to the end of the configuration file.
[junit4]
junit_path = /absolute/path/to/junit-4.12.jar
hamcrest_path = /absolute/path/to/hamcrest-core-1.3.jar
Important
All paths in the configuration file must be absolute to behave as expected.
See CLI arguments for a complete list of arguments that can be configured.
Usage¶
Terminology and conventions¶
repomate-junit4
adds some additional terminology to Repomate that you need
to be familiar with to fully understand the rest of the documentation.
- Production class: A Java file/class in the student repo (written by the student).
- Test class: A Java file/class ending in
Test.java
containing tests for a namesake production class. Test classes are paired with production classes by simply appendingTest
to the production class name. For example,LinkedList.java
would have a test class calledLinkedListTest.java
. - Test directory: A directory named after a master repo, containing tests for the assignments in that repo.
- Reference tests directory (RTD): A directory containing test directories (as defined above).
See the Example use case for a more detailed look at how all of this fits together.
CLI arguments¶
repomate-junit4
adds several new CLI arguments to the repomate clone
command.
-rtd|--reference-tests-dir
- Path to the RTD.
- Can be specified in the configuration file with the
reference_test_dir
option. - Required unless specified in the configuration file.
-junit|--junit-path
- Path to the
junit-4.12.jar
library. - Picked up automatically if on the
CLASSPATH
environment variable. - Can be specified in the configuration file with the
junit_path
option. - Required unless specified on the
CLASSPATH
variable, or in the configuration file.
- Path to the
-ham|--hamcrest-path
- Path to the
hamcrest-core-1.3.jar
library. - Picked up automatically if on the
CLASSPATH
environment variable. - Can be specified in the configuration file with the
hamcrest_path
option. - Required unless specified on the
CLASSPATH
variable, or in the configuration file.
- Path to the
-i|--ignore-tests
- A whitespace separated list of test files (e.g.
LinkedListTest.java
) to ignore.
- A whitespace separated list of test files (e.g.
--disable-security
- Disable the security policy.
-v|--verbose
- Display more verbose information (currently only concerns test failures).
- Long lines are truncated.
-vv|--very-verbose
- Same as
-v
, but without truncation.
- Same as
Example use case¶
Assume that we have a master repo called fibonacci with an assignment to implement a method that returns the n:th Fibonacci number. The master repo could then look like this:
fibonacci
├── README.md
└── src
└── Fibo.java
To be able to test the students’ implementations, we write a test class
FiboTest.java
and put it in our reference tests directory, in a test
directory named after the master repository. The reference test directory would
then look like this.
reference_tests
└── fibonacci
└── FiboTest.java
Note
I strongly recommend having the reference tests in version control.
Now, assume that we have students ham, spam and eggs, and their student
repos ham-fibonacci, spam-fibonacci and eggs-fibonacci. Assuming that the
JUnit4 and Hamcrest jars have been configured as suggested in Configuration,
and that the basic Repomate arguments are configured (see the Repomate config
docs), we can run repomate clone
with repomate-junit4
activated like
this:
$ repomate -p junit4 clone -mn fibonacci -s ham spam eggs -rtd /path/to/reference_tests
[INFO] cloning into student repos ...
[INFO] Cloned into https://some-enterprise-host/some-course-org/inda-18/ham-fibonacci
[INFO] Cloned into https://some-enterprise-host/some-course-org/inda-18/spam-fibonacci
[INFO] Cloned into https://some-enterprise-host/some-course-org/inda-18/eggs-fibonacci
[INFO] executing post clone hooks on repos
[INFO] executing post clone hooks on eggs-fibonacci
[INFO] executing post clone hooks on spam-fibonacci
[INFO] executing post clone hooks on ham-fibonacci
[INFO]
hook results for spam-fibonacci
junit4: SUCCESS
Status.SUCCESS: Test class FiboTest passed!
hook results for eggs-fibonacci
junit4: ERROR
Status.ERROR: multiple production classes found for FiboTest.java
hook results for ham-fibonacci
junit4: ERROR
Status.ERROR: Test class FiboTest failed 1 tests
[INFO] post clone hooks done
Note
The output is color coded when displayed in a terminal.
Let’s digest what happened here. We provided the master repo name (-mn
fibonacci
) and the reference tests directory (-rtd
/path/to/reference_tests
). repomate-junit4
then looked in the test
directory matching the master repo name (i.e. fibonacci) test directory and
found a test class FiboTest.java
. By the naming convention, it knows that
it should now look for a file called Fibo.java
in the student repos. The
following then happened when testing the repos:
- spam-fibonacci: The production class
Fibo.java
was found and passed the test class. - eggs-fibonacci: Multiple files called
Fibo.java
were found, andrepomate-junit4
did not know which one to use. - Duplicate class names are only allowed if their fully qualified names differ (i.e. the classes are in different packages). If production code is supposed to be packaged, the test classes must also be packaged (in the same package). - ham-fibonacci: The production class
Fibo.java
was found, but failed one of the tests. - Running the same command again with-v
or-vv
would display which test failed, and why.
Other common causes of errors include:
- No production class found for a test class.
- Compile error.
- Security policy violation.
- See Security aspects.
This concludes the use case example, I hope you found it enlightening.
Security aspects¶
There are some inconvenient security implications to running untrusted code on
your own computer. repomate-junit4
tries to limit what a student’s code can
do by running with a very strict JVM Security Policy. This is enforced by
the Java SecurityManager. The policy used looks like this:
// empty grant to strip all permissions from all codebases
grant {
};
// the `junit-4.12.jar` needs this permission for introspection
grant codeBase "file:{junit4_jar_path}" {{
permission java.lang.RuntimePermission "accessDeclaredMembers";
}};
This policy disallows student code from doing most illicit things, such as
accessing files outside of the codebases’s directory, or accessing the network.
The {junit4_jar_path}
is dynamically resolved during runtime, and will lend
the actual junit-4.12.jar
archive that is used to run the test classes
sufficient permissions to do so.
This policy seems to work well for introductory courses in Java, but there may be snags because of how restrictive it is. If you find that some permission should definitely be added, please open an issue about it. There are plans to add the ability to specify a custom security policy, but currently, your only choice is to either use this default policy or disable it with –disable-security.
Important
The security policy relies on the correctness of the Java SecurityManager. It is probably not bulletproof, so if you have strict security requirements, you should only run this plugin inside of a properly secured environment (for example, a virtual machine).
repomate-junit4
Module Reference¶
This module reference is intended for developers contributing to
repomate-junit4
and should not be considered a stable API.
junit4¶
Plugin that runs JUnit4 on test classes and corresponding production classes.
Important
Requires javac
and java
to be installed, and having
hamcrest-core-1.3.jar
and junit-4.12.jar
on the local macine.
This plugin performs a fairly complicated tasks of running test classes from pre-specified reference tests on production classes that are dynamically discovered in student repositories. See the README for more details.
-
class
repomate_junit4.junit4.
JUnit4Hooks
[source]¶ -
act_on_cloned_repo
(path)[source]¶ Look for production classes in the student repo corresponding to test classes in the reference tests directory.
Assumes that all test classes end in
Test.java
and that there is a directory with the same name as the master repo in the reference tests directory.Parameters: path ( Union
[str
,Path
]) – Path to the student repo.Return type: HookResult
Returns: a plug.HookResult specifying the outcome.
-
clone_parser_hook
(clone_parser)[source]¶ Add reference_tests_dir argument to parser.
Parameters: clone_parser ( ConfigParser
) – Theclone
subparser.Return type: None
-
_java¶
Utility functions for activities related to Java.
This module contains utility functions dealing with Java-specific behavior, such as parsing package statements from Java files and determining if a class is abstract.
-
repomate_junit4._java.
extract_package
(class_)[source]¶ Return the name package of the class. An empty string denotes the default package.
Return type: str
-
repomate_junit4._java.
extract_package_root
(class_, package)[source]¶ Return the package root, given that class_ is the path to a .java file. If the package is the default package (empty string), simply return a copy of class_.
Raise if the directory structure doesn’t correspond to the package statement.
Return type: Path
-
repomate_junit4._java.
fqn
(package_name, class_name)[source]¶ Return the fully qualified name (Java style) of the class.
Parameters: Return type: Returns: The fully qualified name of the class.
-
repomate_junit4._java.
generate_classpath
(*paths, classpath='')[source]¶ Return a classpath including all of the paths provided. Always appends the current working directory to the end.
Parameters: Return type: Returns: a formated classpath to be used with
java
andjavac
-
repomate_junit4._java.
is_abstract_class
(class_)[source]¶ Check if the file is an abstract class.
Parameters: class – Path to a Java class file. Return type: bool
Returns: True if the class is abstract.
-
repomate_junit4._java.
javac
(java_files, classpath)[source]¶ Run
javac
on all of the specified files, assuming that they are all.java
files.Parameters: Return type: Returns: (status, msg), where status is e.g.
Status.ERROR
and the message describes the outcome in plain text.
-
repomate_junit4._java.
pairwise_compile
(test_classes, java_files, classpath)[source]¶ Compile test classes with their associated production classes.
For each test class:
- Find the associated production class among the
java_files
2. Compile the test class together with all of the .java files in the associated production class’ directory.
Parameters: Return type: Returns: A tuple of lists of HookResults on the form
(succeeded, failed)
- Find the associated production class among the
_junit4_runner¶
-
repomate_junit4._junit4_runner.
get_num_failed
(test_output)[source]¶ Get the amount of failed tests from the error output of JUnit4.
Return type: int
-
repomate_junit4._junit4_runner.
parse_failed_tests
(test_output)[source]¶ Return a list of test failure descriptions, excluding stack traces.
Return type: str