Problem beim Mocken

8u3631984

Bekanntes Mitglied
Hallo zusammen, ich verwende das Mockito Framework. HIer mal Source Code :
Java:
package my.photoalbum.photo.tag;
...

@Builder(setterPrefix = "with", toBuilder = true)
@Entity
@Table(name = "tag")
@ToString
public class Tag implements DatabaseObject {

    @Id
    @GeneratedValue
    @Column(updatable = false)
    @Getter
    private long ID;

    // required parameter
    @NonNull
    @Getter
    private String name;
}

Java:
package my.photoalbum.photo.tag;

...

public interface TagRepository extends JpaRepository<Tag, Long> {

    /**
     * can find a tag object
     *
     * @param name
     * @return the existing tag object or an empty object
     */
    Optional<Tag> findByName(String name);
}

Java:
package my.photoalbum.photo.tag;

import static net.logstash.logback.argument.StructuredArguments.kv;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import my.photoalbum.database.DatabaseService;
import my.photoalbum.photo.geolocation.GeoLocation;
import my.photoalbum.photo.metadata.MetaData;

@Service
@Log4j2
public class TagService extends DatabaseService<Tag> {

    private final TagRepository repository;

    protected TagService(@NonNull TagRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Override
    protected Optional<Tag> getExisting(@NonNull Tag tag) {
        return repository.findByName(tag.getName());
    }

    /**
     * build tag by name
     *
     * @param name
     * @return the build tag object
     */
    protected Tag buildTag(@NonNull String name) {
        var tag = Tag.builder()
                .withName(name)
                .build();

        log.info("build {} ", kv("tag object", tag));
        return tag;
    }

    /**
     * build tags from geo location object
     *
     * @param geolocation
     * @return the build tags
     */
    public List<Tag> buildTag(@NonNull GeoLocation geolocation) {
        List<Tag> tagList = Lists.newArrayList();

        if (!geolocation.getCountry().isEmpty())
            tagList.add(getExistingOrSave(buildTag(geolocation.getCountry())));

        if (!geolocation.getCity().isEmpty())
            tagList.add(getExistingOrSave(buildTag(geolocation.getCity())));

        if (!geolocation.getSuburb().isEmpty())
            tagList.add(getExistingOrSave(buildTag(geolocation.getSuburb())));

        if (!geolocation.getStreet().isEmpty())
            tagList.add(getExistingOrSave(buildTag(geolocation.getStreet())));

        if (!geolocation.getPostCode().isEmpty())
            tagList.add(getExistingOrSave(buildTag(geolocation.getPostCode())));

        return tagList;
    }

    /**
     * build tags from metadata object
     *
     * @param metaData
     * @return the build tags
     */
    public List<Tag> buildTag(@NonNull MetaData metaData) {
        return Lists.newArrayList();
    }
}

So und nun mein Testcode :

Java:
package my.photoalbum.photo.tag;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class TagServiceTest {

    private TagService service;

    @Mock
    private TagRepository repository;

    @BeforeEach
    void init() {
        service = new TagService(repository);
    }

    @Test
    void canGetAllTagOjects() {
        service.getAll();

        verify(repository).findAll();
    }

    @Test
    void canSaveTagObjectIfNotExists() {
        given(repository.findByName("Test"))
                .willReturn(Optional.empty());

        service.getExistingOrSave(mock(Tag.class));

        verify(repository).saveAndFlush(any(Tag.class));
    }

    @Test
    void canBuildTagObjectByName() {
        var name = "TestTagName";
        var tag = service.buildTag(name);

        assertThat(tag).isNotNull();

        assertThat(tag.getName()).isNotNull();
        assertThat(tag.getName()).isEqualTo(name);
    }

}

Im Test canSaveTagObjectIfNotExists kommt folgende Exception :
Java:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
 - this invocation of 'findByName' method:
    repository.findByName(null);
 at my.photoalbum.photo.tag.TagService.getExisting(TagService.java:31)
 - has following stubbing(s) with different arguments:
    1. repository.findByName("Test");
 at my.photoalbum.photo.tag.TagServiceTest.canSaveTagObjectIfNotExists(TagServiceTest.java:42)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
  - stubbing the same method multiple times using 'given().will()' or 'when().then()' API
    Please use 'will().given()' or 'doReturn().when()' API for stubbing.
  - stubbed method is intentionally invoked with different arguments by code under test
    Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
 at my.photoalbum.photo.tag.TagService.getExisting(TagService.java:31)
 at my.photoalbum.photo.tag.TagService.getExisting(TagService.java:18)
 at my.photoalbum.database.DatabaseService.getExistingOrSave(DatabaseService.java:34)
 at my.photoalbum.photo.tag.TagServiceTest.canSaveTagObjectIfNotExists(TagServiceTest.java:45)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Leider bin ich bei meinen Versuchen den Fehler zu behebn nicht weiter gekommen. Hat jemand eine Idee ?
Vielen Dank
 

Oneixee5

Top Contributor
Prüfe mal deine Compiler-Optionen oder verwende die Param-Annotation:
Java:
Optional<Tag> findByName(@Param("name") String name);
 

mrBrown

Super-Moderator
Mitarbeiter
u.U. ist das Problem nicht der Test sondern dein Code und der Test zeigt grad einen Fehler an?

Prüfe mal deine Compiler-Optionen oder verwende die Param-Annotation:
Java:
Optional<Tag> findByName(@Param("name") String name);
Sollte egal sein, wenn das Repo nur gemockt und nicht von Spring bereitgestellt wird?
 

mrBrown

Super-Moderator
Mitarbeiter
Wie sieht denn der Code aus, der angemeckert wird:

Java:
 at my.photoalbum.photo.tag.TagService.getExisting(TagService.java:31)
 at my.photoalbum.photo.tag.TagService.getExisting(TagService.java:18)
 at my.photoalbum.database.DatabaseService.getExistingOrSave(DatabaseService.java:34)

Ich würde da erstmal Mockito vertrauen und davon ausgehen, dass es wirklich den unerwarteten Aufruf mit null gab.
 

8u3631984

Bekanntes Mitglied
Hier ist der COde der Basisklasse
Java:
@Service
public abstract class DatabaseService<T extends DatabaseObject> {

    private final JpaRepository<T, Long> repository;

    protected DatabaseService(@NonNull JpaRepository<T, Long> repository) {
        this.repository = repository;
    }

    /**
     * @return a list with all database objects
     */
    public List<T> getAll() {
        return repository.findAll();
    }

    /**
     * get the existing database object or save a new one
     *
     * @param databaseObject
     * @return the existing or saved database object
     */
    public T getExistingOrSave(@NonNull T databaseObject) {
        return getExisting(databaseObject).orElseGet(() -> save(databaseObject));
    }

    /**
     * check if the databse object exists already
     *
     * @param databaseObject
     * @return the existing database object or an empty object
     */
    protected abstract Optional<T> getExisting(@NonNull T databaseObject);

    /**
     * save the database object
     *
     * @param databaseObject
     * @return the saved database object
     */
    protected T save(@NonNull T databaseObject) {
        return repository.saveAndFlush(databaseObject);
    }
}
 

8u3631984

Bekanntes Mitglied
Ich glaube ich habe das Problem gefunden :
Java:
    @Test
    void canSaveTagObjectIfNotExists() {
        var tag = Tag.builder().withName("TestTag").build();
        
        given(repository.findByName(anyString()))
                .willReturn(Optional.empty());

        service.getExistingOrSave(tag);

        verify(repository).saveAndFlush(any(Tag.class));
    }

Das Feld name ist in der Klasse Tag mit @NonNull annotiert. Daher kommt die Nullpointer Exception
 

mrBrown

Super-Moderator
Mitarbeiter
Daher kommt die Nullpointer Exception
Welche Nullpointer-Exception denn plötzlich?

Fehler wird diese Zeile sein:
service.getExistingOrSave(mock(Tag.class));
Der gemockte Tag hat dann keinen Namen, sondern eben null, was dann bei repository.findByName(tag.getName()); zu dem Aufruf mit null führt, mit dem Mockito nichts anzufangen weiß.

In dem Test solltest du keinen gemockten Tag, sondern eher einen mit Namen Test verwenden.
 

LimDul

Top Contributor
Grundsätzlich gilt - sowenig Mocken wie möglich. Am besten nur externe Resourcen, die man im Test nicht oder nur mit viel Aufwand aufgesetzt bekommt (z.B. externe Webservices).
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
D Spring: Problem beim ausführen eines JUnit Tests. Frameworks - Spring, Play, Blade, Vaadin & Co 4
W DI-Problem in Spring Boot Frameworks - Spring, Play, Blade, Vaadin & Co 4
Z Versuch mit Rest-Api-Tester geben offenbar ein lib Problem Frameworks - Spring, Play, Blade, Vaadin & Co 1
OnDemand Spring Security/Boot/Vaadin Cookie Problem bei iFrame Frameworks - Spring, Play, Blade, Vaadin & Co 4
D Backtracking (Springer-Problem) Frameworks - Spring, Play, Blade, Vaadin & Co 6
B Java Spring Boot - POM-Problem Frameworks - Spring, Play, Blade, Vaadin & Co 8
J Spring Boot Autowired Problem Frameworks - Spring, Play, Blade, Vaadin & Co 2
E Tomcat mit Hibernate und Spring - Problem mit Connection Pool Frameworks - Spring, Play, Blade, Vaadin & Co 5
M Spring property problem Frameworks - Spring, Play, Blade, Vaadin & Co 2
E Springerproblem - Problem Frameworks - Spring, Play, Blade, Vaadin & Co 1
M Problem bei Velocity und Spring Validation Frameworks - Spring, Play, Blade, Vaadin & Co 1
M Problem mit Spring LTW Frameworks - Spring, Play, Blade, Vaadin & Co 5
NoXiD SpringSecurity Problem Frameworks - Spring, Play, Blade, Vaadin & Co 3
B Axis2 1.6 + Spring -> ClassLoader Problem Frameworks - Spring, Play, Blade, Vaadin & Co 0
M Problem mit spring und log4j Frameworks - Spring, Play, Blade, Vaadin & Co 0
M Problem mit spring security Frameworks - Spring, Play, Blade, Vaadin & Co 0
B SpringMVC-EntityManagerFactory-Hibernate-Problem Frameworks - Spring, Play, Blade, Vaadin & Co 1
M Problem mit Hibernate und Spring Frameworks - Spring, Play, Blade, Vaadin & Co 0
M Problem mit Gilead und Spring Frameworks - Spring, Play, Blade, Vaadin & Co 1
B SpringLayout Problem Frameworks - Spring, Play, Blade, Vaadin & Co 3
tfa Problem mit Maven, Tomcat, Spring und XML-Schema Frameworks - Spring, Play, Blade, Vaadin & Co 0
H JSF + SpringSecurity Problem Frameworks - Spring, Play, Blade, Vaadin & Co 2
A Problem mit Spring-WS und Marshalling Frameworks - Spring, Play, Blade, Vaadin & Co 0
H file upload problem mit spring Frameworks - Spring, Play, Blade, Vaadin & Co 33
H Spring: Problem mit CommandClass in SimpleFormController (aus Step-by-Step Tutorial) Frameworks - Spring, Play, Blade, Vaadin & Co 1
dunhillone Problem mit Spring & Hibernate Sessions Frameworks - Spring, Play, Blade, Vaadin & Co 2
dunhillone Problem mit Spring & Hibernate Sessions Frameworks - Spring, Play, Blade, Vaadin & Co 2
M Spring DM: Problem mit Tomcat als OSGI-Service Frameworks - Spring, Play, Blade, Vaadin & Co 2
chik Spring ACEGI Problem Frameworks - Spring, Play, Blade, Vaadin & Co 1
M JSF Navigation - Spring Security Logout Problem Frameworks - Spring, Play, Blade, Vaadin & Co 5
R Probleme beim abfragen von untergeordneten Tabellen Frameworks - Spring, Play, Blade, Vaadin & Co 2
8u3631984 Spring JPA Probleme beim SPeichern von Sets Frameworks - Spring, Play, Blade, Vaadin & Co 3
8u3631984 Spring JDBC Probleme beim Spaltennamen Frameworks - Spring, Play, Blade, Vaadin & Co 3
R Tests beim extracten von sub value schlägt fehl Frameworks - Spring, Play, Blade, Vaadin & Co 6
8u3631984 Probleme beim Starten von TestContainer Frameworks - Spring, Play, Blade, Vaadin & Co 4
8u3631984 Beim WebMVC Test wird Resource File nicht gefunden. Frameworks - Spring, Play, Blade, Vaadin & Co 1
8u3631984 Cross-Origin beim Abrufen von Spring Endpoint Frameworks - Spring, Play, Blade, Vaadin & Co 1
L Hilfe beim Erstellen einer Java Web Anwendung gesucht Frameworks - Spring, Play, Blade, Vaadin & Co 5
Dimax Spring App Probleme beim Ausführen auf dem Tomcat Server Frameworks - Spring, Play, Blade, Vaadin & Co 1
JanKrieger05 Error beim Speichern von Daten mit nullable JoinColumn Frameworks - Spring, Play, Blade, Vaadin & Co 0
Xentox501 Jump & Run: Beim springen bewegen(rechts,links) Frameworks - Spring, Play, Blade, Vaadin & Co 1
J Resolver für XML Schema Location beim Laden des Spring Application Context Frameworks - Spring, Play, Blade, Vaadin & Co 1
T JTable + JScrollePane Größe "springt" beim resizen des Fensters Frameworks - Spring, Play, Blade, Vaadin & Co 4
E Fehlermeldung von Spring Security beim Einloggen Frameworks - Spring, Play, Blade, Vaadin & Co 1
S Spring Security mit oauth2 in lokaler Konfiguration principal mocken Frameworks - Spring, Play, Blade, Vaadin & Co 0

Ähnliche Java Themen

Neue Themen


Oben