Bład podczas mockowania metody

0

Witajcie,
Napotkałem na problem podczas mockowania metody. Poniżej mój kod

    @Test
    public void shouldAddPost() {
        String content = "content";
        Integer id = 1;

        sut.reply(content, id);

        verify(postService, times(1)).addPost(eq(id), eq(principal.getUsername()), any(Post.class));
    }

    public void addPost(Integer topicId, String username, Post post) {
        User u = this.userService.getUser(username);
        Topic t = this.topicRepository.findOneById(topicId);
        t.addPost(post);
        u.addPost(post);
        this.userService.save(u);
        this.topicRepository.save(t);
    }

    @Override
    public int hashCode() {
        int result = topic.hashCode();
        result = 31 * result + date.hashCode();
        result = 31 * result + message.hashCode();
        return result;
    }

Wyjątek zostaje wyrzucony dla tego ponieważ zmienna topic ma wartość null. Podczas normalnego działania kodu (nie testowania) wartość tej zmiennej powinna zostać ustawiona w metodzie addPost dla obiektu Topic. Dziwi mnie dlaczego metoda hashCode jest w ogóle wykonywana, ponieważ na bład napotykam w linii

verify(postService, times(1)).addPost(eq(id), eq(principal.getUsername()), any(Post.class));

Mój wyjątek:

java.lang.NullPointerException
	at pl.zaprogramowany.cms.entity.Post.hashCode(Post.java:122)

Jak temu zaradzić?

0

Nie bardzo rozumiem pytanie. Robisz tu jakieś addPost na jakichś obiektach i zgaduje że masz tam w nich jakiś HashSet albo HashMap. Co ten test wg ciebie w ogóle testuje tak btw? o_O

0

Ma testować czy została wykonana metoda addPost(). Problem w tym że w linijce z verify ta metoda jest wykonywana, na nie wiadomej instancji obiektu bez zainitializowanych pól, przez co sypie się hashCode(), który również jest wykonywany przez mockito nie wiadomo dlaczego

0

OMG ale co to jest w ogóle za kod? To jest kod tego serwisu czy co to jest za kod? Możesz łaskawie pokazać co konkretnie robisz? Jak i co mockujesz i jak wygląda kod na którym pracujesz? Bo wstawiłeś jakieś skrawki z których w sumie nic nie wynika.

Niemniej ja nadal widzę taki sam błąd: mockujesz i chcesz weryfikować czy wykona się metoda na tym serwisie, ale metoda addPost którą pokazałeś ROBI TEŻ INNE RZECZY i to one sie sypią. Przecież ty tam normalnie wywołujesz tą metodę więc to dość logiczne że się wysypie w takiej sytuacji.

0

Ten kod zajmuje trochę miejsca, chciałem go skrócić do minimum żeby post nie był ogromny :)

    private User principal = new User("foo", "foo", "foo", true);

    @Before
    public void given() {
        when(SpringUtils.getPrincipalUsername()).thenReturn(principal.getUsername());
    }

    @Test
    public void shouldAddPost() {
        String content = "content";
        Integer id = 1;
 
        sut.reply(content, id);
 
        // W poniższej linijce wyrzucany jest wyjątek, który pochodzi z metody hashCode()
        verify(postService, times(1)).addPost(eq(id), eq(principal.getUsername()), any(Post.class));
    }
    @RequestMapping(value = "/reply", method = RequestMethod.POST)
    public String reply(@RequestParam("content") String content, @PathVariable(value = "id") Integer id) {
        this.postService.addPost(id, SpringUtils.getPrincipalUsername(), new Post(content));
        return "redirect:";
    }
    public void addPost(Integer topicId, String username, Post post) {
        User u = this.userService.getUser(username);
        Topic t = this.topicRepository.findOneById(topicId);
        t.addPost(post);
        u.addPost(post);
        this.userService.save(u);
        this.topicRepository.save(t);
    }
    public class User {
        @OneToMany(mappedBy = "creator", cascade = CascadeType.ALL)
        private List<Post> posts = new ArrayList<>();

        public void addPost(Post post) {
            post.setCreator(this);
            this.posts.add(post);
        }

    }
    public class Topic {
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "topic")
        private List<Post> posts = new ArrayList<>();

        public void addPost(Post post) {
            post.setTopic(this);
            this.posts.add(post);
        }
    }
    public class Post {
        @ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name = "topic_id", nullable = false)
        private Topic topic;

        @ManyToOne
        @JoinColumn(name = "user_id", nullable = false)
        private User creator;

        protected void setCreator(User creator) {
            this.creator = creator;
        }
        protected void setTopic(Topic topic) {
            this.topic = topic;
        }
        @Override
        public int hashCode() {
            // W tej linijce wyrzucany jest wyjątek, ponieważ topic jest null
            int result = topic.hashCode();
            result = 31 * result + date.hashCode();
            result = 31 * result + message.hashCode();
            return result;
        }
    }
0

No to teraz zapnij się debugerem w tym kontrolerze jak wykonujesz test i zobacz czy postService jest mockiem. Ja zgaduje że wcale nie jest.

0

Ja obstawiam, że zapomniałeś wstrzyknąć mocka. Zabrakło @InjectMocks jeśli korzystasz z field injection albo po prostu nie wywołałeś konstuktora testowanego obiektu (SUT) z odpowiednimi parametrami (bo nie widzę tego w @Before), jeśli z constructor injection.

Zauważyłem jeszcze coś podejrzanego:

SpringUtils.getPrincipalUsername()

To mi wygląda na mockowanie statica (robione źle). Nie masz kontekstu, to IMO nie zadziała. Zrób wrapper albo użyj PowerMock.

0

Załączam screen. postService jest mockiem.

    @InjectMocks
    private TopicController sut;

    @Mock
    private PostService postService;

W given oczywiście mam MockitoAnnotations.initMocks(this);

0

@Zaprogramowany no dobra ale czy ten postService jako pole twojego controllera też jest na pewno mockiem? Bo ja myśle że wcale nie jest.

0

Masz:

    @InjectMocks
    private TopicController sut;

Pownieneś mieć:

    @InjectMocks
    private TopicController sut = new TopicController();

@InjectMocks nie tworzy obiektu, musisz go stworzyć. Co najwyżej wstrzykuje mocki (refleksja), ale obiekt musi być już utworzony!

1 użytkowników online, w tym zalogowanych: 0, gości: 1