Versions and Migrating from 1000.x¶
0260.9.0 was published accidentally (instead of 0.9.0); 1000.0.0 acts as 1.0.0. 2000.0.0 is
the first release of the Ares 2 / Java 25 line and contains the breaking changes below.
| 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; 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 with 2000.0.0. 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.
Changes in 2026.11.1¶
- One failure format for behaviour failures (#34). Exceptions of student code (
invoke,newObj,ConstructorWrapper.invoke),invokeExpectingExceptionandtestGettersSettersreport with the same 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: ...", "Failed to invoke constructor ...", "... should throw X, but: ..." and "Getter/setter test for attribute ...: ✅/❌ ..." are gone.
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.- Values in messages:
double/floatwith 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. -
New:
Failurefor your own checks, see Reporting failures. The old message constants are kept but@Deprecated. -
Unexpected modifiers are reported (#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) is now a deviation: the structural test fails with "unexpected modifier: ...". Existing structural tests can turn red on student code with extra modifiers. Mark harmless extras as optional with a?suffix, e.g."public", "final?"for a utility class. See Modifiers. - Nested classes: a wrapper of a
staticnested class must now expectstatic. - A missing expected
staticis a deviation instead ofMISSING: behavioural tests go on and call the method or read the attribute on the default object. @LevenshteinTestand@HiddenLevenshteinTestreset attributes that are unexpectedlystaticbefore each test (StaticStateReset).- An inner class where a
staticnested class is expected can still be instantiated (the outer instance is created automatically). LevenshteinSettings.setUnexpectedModifiers(UnexpectedModifiers.IGNORE)behaves like before (only an unexpectedstaticof attributes and methods is reported; a missingstaticisMISSING).- 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.
Changes in 2026.11.0¶
structuralTestFactoryno longer generates tests for empty groups (e.g.Attributes[X]for a class without attributes,Constructors[X]for an interface). Such tests 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...).- A wrong number of arguments for
invoke(...),ConstructorWrapper.invoke(...)orgetObj(forceNew, constructorWrapper, args...)is now anIllegalArgumentException(an error in the test) instead of a failed test. Pass a single array argument as(Object) array. - Numeric conversions no longer change values 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. - An
AssertionErrorfrom inside a call (from Ares, a mock or a conversion) now gets the arguments and the text ofinvokeWithContextas well. - New:
ClassWrapper.newObjWithoutConstructor(),newObjOverriding(...)andmock()keep tests independent of other student members (#30). See Independent tests. - New: student classes as attribute, return and parameter types (#33).
AttributeWrapper,MethodWrapperandConstructorWrapperaccept aClassWrapper(e.g.ClassWrapper.reference("Drummer", pkg)) or a supplier of one; 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. - A literal
nullas return type (new MethodWrapper<>(this, "m", null, ...)) is now ambiguous; write(Class<Object>) null. - A
nullentry in a parameter type array now throwsIllegalArgumentExceptionwhen the wrapper is built.