Versions and Migrating¶
What changed between releases and how to update existing tests. If you start a new exam, you do not need this page: the other guides describe the current release.
| Version | Highlights |
|---|---|
| 2026.11.1 | One failure format for behaviour failures (Failure), unexpected modifiers reported, student classes as member types, objects without constructor and mocks, docs site |
| 2026.11.0 | testGettersSetters (getter/setter tests with setter conditions and own sample values), failing example solution |
| 2000.0.0 | First release on Ares 2 and Java 25 |
| 1000.0.0 | Last release on Ares 1 (0260.9.0 was published by accident instead of 0.9.0; 1000.0.0 acts as 1.0.0) |
Upgrading to 2026.11.1¶
The changes since 2000.0.0, for test suites written against 2000.0.0 or 2026.11.0. Coming from 1000.x, first apply the 2000.0.0 changes.
What can turn existing tests red¶
- Unexpected modifiers deviate (#35). A modifier of the student's element that is neither expected,
optional nor implicit (e.g.
private static boolean[] spotlightswhereprivateis expected, an extraabstract,finalorsynchronized) fails the structural test with "unexpected modifier: ...". Mark harmless extras as optional with a?suffix, e.g."public", "final?"for a utility class. See Modifiers. - A wrapper of a
staticnested class must now expectstatic. - To keep the old behaviour, set
LevenshteinSettings.setUnexpectedModifiers(UnexpectedModifiers.IGNORE). - A missing expected
staticis a deviation instead ofMISSING: behavioural tests go on and call the method or read the attribute on the default object. - Messages of behaviour failures changed (#34). Exceptions of student code (
invoke,newObj,ConstructorWrapper.invoke),invokeExpectingExceptionandtestGettersSettersreport with one block ofMethod:/Scenario:/Input:/Expected:/Actual:lines (German:Methode:,Szenario:,Eingabe:,Erwartet:,Tatsächlich:). Tests that assert on message texts need updating: - "Calling method ... threw an exception: ...", "... should throw X, but: ..." and "Getter/setter test for attribute ...: ✅/❌ ..." are gone. An exception thrown by a student constructor is reported in the block, too.
Arguments: (...)became theInput:line; the text ofinvokeWithContextis theScenario:line.testGettersSettersshows only the first failing case plus "(n of m cases failed)" instead of one line per subtest. A missing getter or setter fails with the short structural message.double/floatvalues are shown with two decimals (2.50,LevenshteinSettings.setDecimals).- The
AssertionErrorno longer has the student's exception as cause (no stack trace, noCaused by). Read the exception frominvokeExpectingExceptionif a test needs it. - A
StackOverflowErrorof student code is a normal failure with a hint on endless recursion instead of being rethrown. - The old message constants are kept but
@Deprecated. - No structural tests for empty groups.
structuralTestFactoryno longer generates tests such asAttributes[X]for a class without attribute wrappers orConstructors[X]for an interface. They always passed, also for an untouched template. If your Artemis exercise gives points for one of them, remove it there, or keep the old tests withstructuralTestFactory(level, false, wrappers...). - Numbers are no longer changed silently.
Utils.safeCast,setValueand arguments for a deviating numeric parameter type fail with a readable message if the value does not fit the student's type (e.g.2.5→int,200→byte). Before,safeCastandsetValuetruncated or wrapped such values. Arguments are now converted to a deviating numeric parameter type (2.5→float); before, the call failed. - A wrong number of arguments for
invoke(...),ConstructorWrapper.invoke(...)orgetObj(forceNew, constructorWrapper, args...)is anIllegalArgumentException(an error in the test) instead of a failed test. Pass a single array argument as(Object) array. - Getters and setters compare arrays by content (
Objects.deepEquals). To require the same object, setLevenshteinSettings.setGettersSettersRequireSameObject(true).
API changes¶
- A literal
nullas return type (new MethodWrapper<>(this, "m", null, ...)) is ambiguous now; write(Class<Object>) null. - A
nullentry in a parameter type array throwsIllegalArgumentExceptionwhen the wrapper is built. - With
@LevenshteinTest, attribute wrappers are looked up before each test. ConfigureLevenshteinSettingsin a static initializer or@BeforeAll; changes inside a test method come too late for them.
New features¶
Failurefor your own checks, so students see the same format there. See Reporting failures.- Optional modifiers with a
?suffix, andgetMissingModifiers()/getUnexpectedModifiers()on every wrapper. StaticStateReset:@LevenshteinTestand@HiddenLevenshteinTestreset attributes that are unexpectedlystaticbefore each test, so results do not depend on the order of the tests.- Inner instead of nested class: an inner class where a
staticnested class is expected can still be instantiated (the outer instance is created automatically). - Student classes as member types (#33).
AttributeWrapper,MethodWrapperandConstructorWrapperaccept aClassWrapper(e.g.ClassWrapper.reference("Drummer", pkg)) or a supplier of one as type; parameter lists can be anObject[]that mixes them withClass<?>. Replace helpers like a copiedTypeWrapper.resolve(name)with Byte Buddy placeholder classes by these. See Student classes as member types. - Independent tests (#30):
ClassWrapper.newObjWithoutConstructor(),newObjOverriding(...)andmock(). See Independent Tests and Mocks. - An
AssertionErrorfrom inside a call (from Ares, a mock or a conversion) gets the arguments and the text ofinvokeWithContextas well. - Docs site with search and the Javadoc: https://valentinherrmann.github.io/Levenshtein-Testing-Framework/.
Migrating from 1000.x to 2000¶
2000.0.0 is the first release of the Ares 2 / Java 25 line and contains these breaking changes:
| 1000.x | 2000.0.0 |
|---|---|
Ares 1 (de.tum.in.ase:artemis-java-test-sandbox) |
Ares 2 (de.tum.cit.ase:ares, provided), Java 25 |
@LevenshteinTest = Ares 1 security annotations; the sandbox was never active because no @Public/@Hidden was included |
@LevenshteinTest = @Public @StrictTimeout(5) @MirrorOutput (2026.11.1 adds StaticStateReset); plus @Policy + SecurityPolicy.yaml in the exam |
io.github.valentinherrmann.test.TestSettings constants (inlined at compile time, not changeable) |
io.github.valentinherrmann.levenshtein.LevenshteinSettings setters |
io.github.valentinherrmann.test.Messages.X (String) |
io.github.valentinherrmann.levenshtein.Messages.X.get() / .format(...) |
TestSettings.BASE_PACKAGE, variant |
in your own Constants |
getObj(boolean forceNew, boolean useByteBuddy), useByteBuddy=false for private members |
getObj(boolean forceNew); wrappers delegate to getObj(forceNew, constructorWrapper, args...). Abstract classes and interfaces always use Byte Buddy, concrete classes never |
getObj(boolean useByteBuddy) (returned the cached instance) |
getObj() (cached) or newObj() / getObj(true) (new) |
getDynamicSubclassObj(Class<?>[] paramTypes, args...) |
getDynamicSubclassObj(constructorWrapper, args...) |
Utils.saveCast(...) |
Utils.safeCast(...) |
getMethodsWrappers() |
getMethodWrappers() |
setObj writes obj directly |
setCachedObj(obj) |
| Exceptions from student code: generic failure | type and message in the failure, invokeExpectingException(...) |
Gradle or Maven? Both work. The coordinates are unchanged
(io.github.valentinherrmann:levenshtein-testing-framework), but a 1000.x exam repository also needs the
Ares 2 build wiring (weaving, agent, reserved-package guard). Start from the
Gradle
or Maven
template and see Ares 2 Setup in Detail.