From 106a358178f8e1910bc3fcc93975e3383568b08a Mon Sep 17 00:00:00 2001 From: Martin Mladenov <30376060+martinmladenov@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:00:16 +0300 Subject: [PATCH] Configure Mockito to disable the Objenesis class cache (#273) * Add test for Mockito meta test issue * Fix Mockito meta test issue by clearing ObjenesisBase instantiator cache when replacing the classloader * Add another meta test just to be sure * Revert "Fix Mockito meta test issue by clearing ObjenesisBase instantiator cache when replacing the classloader" This reverts commit ec6611c0399d634d7eae562cb6a014b1539b0226. * Disable Objenesis cache using a custom MockitoConfiguration --- .../configuration/MockitoConfiguration.java | 12 +++++ .../integration/LibraryMetaTestsTest.java | 8 +++ ...nmentWithCustomExceptionConfiguration.java | 51 +++++++++++++++++++ ...gAssignmentWithCustomExceptionLibrary.java | 29 +++++++++++ ...CustomExceptionWrongWithoutAssertions.java | 29 +++++++++++ 5 files changed, 129 insertions(+) create mode 100644 andy/src/main/java/org/mockito/configuration/MockitoConfiguration.java create mode 100644 andy/src/test/resources/grader/fixtures/Config/MockingAssignmentWithCustomExceptionConfiguration.java create mode 100644 andy/src/test/resources/grader/fixtures/Library/MockingAssignmentWithCustomExceptionLibrary.java create mode 100644 andy/src/test/resources/grader/fixtures/Solution/MockingAssignmentWithCustomExceptionWrongWithoutAssertions.java diff --git a/andy/src/main/java/org/mockito/configuration/MockitoConfiguration.java b/andy/src/main/java/org/mockito/configuration/MockitoConfiguration.java new file mode 100644 index 000000000..eb17b3212 --- /dev/null +++ b/andy/src/main/java/org/mockito/configuration/MockitoConfiguration.java @@ -0,0 +1,12 @@ +package org.mockito.configuration; + +// The presence of this class configures Mockito to disable the Objenesis cache. +// Caching causes problems when we dynamically replace classes in meta tests. + +@SuppressWarnings("unused") +public class MockitoConfiguration extends DefaultMockitoConfiguration { + @Override + public boolean enableClassCache() { + return false; + } +} diff --git a/andy/src/test/java/integration/LibraryMetaTestsTest.java b/andy/src/test/java/integration/LibraryMetaTestsTest.java index 9faba1b6b..3399b2e44 100644 --- a/andy/src/test/java/integration/LibraryMetaTestsTest.java +++ b/andy/src/test/java/integration/LibraryMetaTestsTest.java @@ -130,4 +130,12 @@ void somePenaltyMetaTestFailingWithWeights() { .has(failedMetaTest("DoesNotApplyLastCarry")); } + @Test + void metaTestsWithMockitoAndCustomException() { + Result result = run("MockingAssignmentWithCustomExceptionLibrary", "MockingAssignmentWithCustomExceptionWrongWithoutAssertions", "MockingAssignmentWithCustomExceptionConfiguration"); + + assertThat(result.getMetaTests().getPassedMetaTests()).isEqualTo(0); + assertThat(result.getMetaTests().getTotalTests()).isEqualTo(2); + } + } \ No newline at end of file diff --git a/andy/src/test/resources/grader/fixtures/Config/MockingAssignmentWithCustomExceptionConfiguration.java b/andy/src/test/resources/grader/fixtures/Config/MockingAssignmentWithCustomExceptionConfiguration.java new file mode 100644 index 000000000..c5702e3e4 --- /dev/null +++ b/andy/src/test/resources/grader/fixtures/Config/MockingAssignmentWithCustomExceptionConfiguration.java @@ -0,0 +1,51 @@ +package delft; + +import nl.tudelft.cse1110.andy.codechecker.checks.Comparison; +import nl.tudelft.cse1110.andy.codechecker.checks.MethodCalledAnywhere; +import nl.tudelft.cse1110.andy.codechecker.checks.MockClass; +import nl.tudelft.cse1110.andy.codechecker.checks.MockitoVerify; +import nl.tudelft.cse1110.andy.codechecker.engine.AndCheck; +import nl.tudelft.cse1110.andy.codechecker.engine.CheckScript; +import nl.tudelft.cse1110.andy.codechecker.engine.SingleCheck; +import nl.tudelft.cse1110.andy.config.MetaTest; +import nl.tudelft.cse1110.andy.config.RunConfiguration; +import nl.tudelft.cse1110.andy.execution.mode.Mode; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Configuration extends RunConfiguration { + + @Override + public Mode mode() { + return Mode.GRADING; + } + + @Override + public Map weights() { + return new HashMap<>() {{ + put("coverage", 0.0f); + put("mutation", 0.0f); + put("meta", 1.0f); + put("codechecks", 0.0f); + }}; + } + + @Override + public List classesUnderTest() { + return List.of("delft.MyService"); + } + + @Override + public List metaTests() { + return List.of( + MetaTest.withStringReplacement("my meta test", + "a == 10", + "a == 15"), + MetaTest.withStringReplacement("another meta test", + "a == 10", + "a == 20") + ); + } +} diff --git a/andy/src/test/resources/grader/fixtures/Library/MockingAssignmentWithCustomExceptionLibrary.java b/andy/src/test/resources/grader/fixtures/Library/MockingAssignmentWithCustomExceptionLibrary.java new file mode 100644 index 000000000..ca413da08 --- /dev/null +++ b/andy/src/test/resources/grader/fixtures/Library/MockingAssignmentWithCustomExceptionLibrary.java @@ -0,0 +1,29 @@ +package delft; + +class MyService { + private final AnotherService anotherService; + + public MyService(AnotherService anotherService) { + this.anotherService = anotherService; + } + + public boolean myMethod(int a) { + if (a == 10) { + return false; + } + + try { + return anotherService.anotherMethod(); + } catch (MyException e) { + return false; + } + } + +} + +interface AnotherService { + boolean anotherMethod() throws MyException; +} + +class MyException extends Exception { +} diff --git a/andy/src/test/resources/grader/fixtures/Solution/MockingAssignmentWithCustomExceptionWrongWithoutAssertions.java b/andy/src/test/resources/grader/fixtures/Solution/MockingAssignmentWithCustomExceptionWrongWithoutAssertions.java new file mode 100644 index 000000000..25589de88 --- /dev/null +++ b/andy/src/test/resources/grader/fixtures/Solution/MockingAssignmentWithCustomExceptionWrongWithoutAssertions.java @@ -0,0 +1,29 @@ +package delft; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.*; +import java.time.*; +import java.util.stream.*; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.*; +import org.junit.jupiter.params.provider.*; +import org.mockito.*; + +class MyServiceTest { + + @Test + void test() throws MyException { + var anotherService = Mockito.mock(AnotherService.class); + var myService = new MyService(anotherService); + + when(anotherService.anotherMethod()).thenThrow(MyException.class); + + boolean result = myService.myMethod(1); + } + +}