- Notifications
You must be signed in to change notification settings - Fork 45
Description
Description
No test cases are generated for methods involving Java Optional<T> class. UtErrors are generated by the engine during traverse due to ClassNotFound exception: UtOptional class can't be loaded. This behavior may be reproduced using the Idea plugin, but models are successfully generated for the same code in the engine unit tests.
To Reproduce
Generate unit tests for the sample method:
import java.util.Optional; public class OptionalExamples { public Optional<Integer> nonEmptyIfPositive(int n) { if (n > 0) { return Optional.of(n); } else { return Optional.empty(); } } } Expected behavior
Two tests are generated, one for each branch in the code (see Additional context for more details).
Actual behavior
Errors are reported:
public class OptionalExamplesTest { ///region Test suites for executable collections.OptionalExamples.nonEmptyIfPositive ///region Errors report for nonEmptyIfPositive public void testNonEmptyIfPositive_errors() { // Couldn't generate some tests. List of errors: // // 2 occurrences of: // org.utbot.engine.overrides.collections.UtOptional } ///endregion ///endregion } Environment
Mockito: any configuration. Test framework: JUnit5.
Additional context
The primary error reason: UtOptional wrapper is used instead of Optional, but the class loader used by the test generator in the plugin can't find it. It's OK (engine-specific wrappers should never leak to the user), but shouldMock function checks the class and fails with ClassNotFound exception.
Adding a check to shouldMock fixes the exception, but the execution path corresponding to Optional.empty() return value is lost unless checkNpeForFinalFields setting is set to true (it is false by default). See SootField.shouldBeNotNull() declared in Extensions.kt.
A similar code sample that uses OptionalInt instead of Optional<Integer> is processed without any problems, because primitive field types are never mocked so no class check is performed.
Code sample:
public OptionalInt nonEmptyOptionalIntIfPositive(int n) { if (n > 0) { return OptionalInt.of(n); } else { return OptionalInt.empty(); } } Generated tests:
///region SUCCESSFUL EXECUTIONS for method nonEmptyOptionalIntIfPositive(int) /** * <pre> * Test executes conditions: * {@code (n > 0): True } * invokes: * OptionalInt::of once * returns from: {@code return OptionalInt.of(n); } * </pre> */ @Test @DisplayName("nonEmptyOptionalIntIfPositive: n > 0 : True -> return OptionalInt.of(n)") public void testNonEmptyOptionalIntIfPositive_NGreaterThanZero() { OptionalExamples optionalExamples = new OptionalExamples(); OptionalInt actual = optionalExamples.nonEmptyOptionalIntIfPositive(1); OptionalInt expected = of(1); assertTrue(deepEquals(expected, actual)); } /** * <pre> * Test executes conditions: * {@code (n > 0): False } * </pre> */ @Test @DisplayName("nonEmptyOptionalIntIfPositive: -> n > 0 : False") public void testNonEmptyOptionalIntIfPositive_NLessOrEqualZero() throws ClassNotFoundException, Exception { Class optionalIntClazz = Class.forName("java.util.OptionalInt"); OptionalInt prevEMPTY = ((OptionalInt) getStaticFieldValue(optionalIntClazz, "EMPTY")); try { OptionalInt empty = empty(); setStaticField(optionalIntClazz, "EMPTY", empty); OptionalExamples optionalExamples = new OptionalExamples(); OptionalInt actual = optionalExamples.nonEmptyOptionalIntIfPositive(0); assertTrue(deepEquals(empty, actual)); } finally { setStaticField(OptionalInt.class, "EMPTY", prevEMPTY); } } ///endregion Metadata
Metadata
Assignees
Labels
Type
Projects
Status