Problem beim Mocken von Record Klassen

8u3631984

Bekanntes Mitglied
Hallo zusammen.
Ich möchte folgenden Unit Test gerne schreiben :
Java:
    private CSVSamsMatchDataImporter unitUnderTest;

    @Mock
    private CSVMatchDataDownloader csvMatchDataDownloader;

    @Mock
    private CSVSamsMatchDataParser csvSamsMatchDataParser;

    @Mock
    private SamsModelService samsModelService;

    @BeforeEach
    public void init() {
        unitUnderTest = new CSVSamsMatchDataImporter(csvMatchDataDownloader, csvSamsMatchDataParser, samsModelService);
    }

    @Test
    void canImportCSVMatchData() throws MalformedURLException {
        given(csvMatchDataDownloader.downloadFileFromURL(any()))
                .willReturn(Optional.of(Paths.get("src", "test", "resources", "TestData", "csv", "CommaSeparatedMatchWithoutResult.csv")));

        unitUnderTest.importMatchDataFromURL(new URL(CSV_MATCH_DATA_URL));
    }

Die Model Klasse :
Code:
@Service
@Log4j2
public record SamsModelService(@NonNull SamsAssociationService associationService,
                               @NonNull SamsSeasonService seasonService,
                               @NonNull SamsCompetitionService competitionService,
                               @NonNull SamsTeamService teamService,
                               @NonNull SamsMatchStatisticService matchStatisticService,
                               @NonNull SamsMatchService matchService) implements ModelService {

Und hier nun der Fehler :
Code:
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.

Underlying exception : java.lang.IllegalArgumentException: Could not create type
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class SamsModelService.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

Ich habe bereits die Mockito Abhängigkeit hinzugefügt :
Code:
    implementation "org.mockito:mockito-inline:4.7.0"
    testImplementation "org.mockito:mockito-inline:4.7.0"
 
Zuletzt bearbeitet:
Das mit dem Mockito kann ich gerade so nicht sagen - kannst Du ein kleines Beispielprojekt erstellen um das so nachzuvollziehen?

Generell ist das Vorgehen so aber auch nicht wirklich gut. Records sind nun einmal nicht als Beans gedacht:
  • Du hast Getter und damit gibt der Service auch die internen Dinge wieder. Das ist so nicht gewollt.
  • Die public Methoden sind in der Regel @Transactional
  • equals / hashcode sind bei Services unüblich
  • auto proxying ist da dann nicht unterstützt

Die Verwendung von Records als Beans / Services ist also eine eher schlechte Idee.

Siehe dazu z.B. auch https://stackoverflow.com/questions...cords-with-service-restcontroller-annotations.
 
Hast du alle Schritte unter https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#Mocking_Final befolgt?
Insbesondere:
This mock maker is turned off by default because it is based on completely different mocking mechanism that requires more feedback from the community. It can be activated explicitly by the mockito extension mechanism, just create in the classpath a file /mockito-extensions/org.mockito.plugins.MockMaker containing the value mock-maker-inline.
und:
This mock maker has been designed around Java Agent runtime attachment ; this require a compatible JVM, that is part of the JDK (or Java 9 VM). When running on a non-JDK VM prior to Java 9, it is however possible to manually add the Byte Buddy Java agent jar using the -javaagent parameter upon starting the JVM.
 
Vielen Dank mit der Umstellung auf class hat es funktioniert - auch dein Argument zu Records hat mich überzeugt.
Vielen Dank für die Hilfe
 
Erst einmal freut es mich, dass ich Dir mit diesem generellen Hinweis weiter helfen konnte.

Ich möchte da nur kurz noch einen Punkt ausführen, weil es im Thread angeklungen ist und Andere ggf. auch über diesen Thread stolpern werden:

Wenn man sich das jar File von mockito-inline anschaut, dann findet man, dass da kaum mehr drin ist als eben diese mockito-extensions/org.mockito.plugins.MockMaker Datei:
Code:
Archive:  ../mockito-inline-4.7.0.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF   
   creating: mockito-extensions/
  inflating: mockito-extensions/org.mockito.plugins.MemberAccessor 
  inflating: mockito-extensions/org.mockito.plugins.MockMaker 
  inflating: LICENSE
(Und da ist dann auch tatsächlich nur "mock-maker-inline" in dieser Datei.)

Daher dürfte das beim TE nicht gefehlt haben - diese Abhängigkeit hat er ja gleich doppelt drin.
 

Zurück
Oben