Mockito: несколько вызовов имитируемого UriBuilder продолжают добавляться к исходному URI - PullRequest
1 голос
/ 28 мая 2020

В настоящее время я пишу несколько модульных тестов для устаревшего кода в приложении rest api. Один конкретный вызов api создает список URI с использованием API UriInfo от Jax-RS. Когда я издеваюсь над этим интерфейсом, я могу запустить тесты, но каждый вызов интерфейса, похоже, повторно использует один и тот же объект URI и добавляется к нему снова и снова, а не новый объект URI, передаваемый в тестируемый код. У меня есть образец класса с тестом, который демонстрирует проблему:

import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;

@Stateless
@Path("/")
public class MockitoUrl {

    @PersistenceContext(name = "MockitoTestPU")
    private EntityManager em;
    @Context
    private UriInfo uriInfo;

    @Path("system")
    @GET
    @Produces("text")
    public List<URI> generateUris() {
        List<URI> uris = new LinkedList<>();
        for (int i=1;i<5;i++) {
            final URI uri = uriInfo.getBaseUriBuilder().path(
                    MockitoUrl.class, "generateUris").build("test");
            System.out.println(uri.toString());
        }
        return uris;
    }

}

Модульный тест:

import java.net.URI;
import java.util.List;
import javax.persistence.EntityManager;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
import org.mockito.MockitoAnnotations;

public class MockitoUrlTest {

    @Mock
    private EntityManager em;
    @Mock
    private UriInfo uri;
    @InjectMocks
    MockitoUrl mockitoUrl;

    public MockitoUrlTest() {
    }

    @Before
    public void setUp() {
        mockitoUrl = new MockitoUrl();
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGenerateUris() throws Exception {
        System.out.println("generateUris");
        String baseUri = "http://server1/api";

        when(uri.getBaseUriBuilder()).thenReturn(UriBuilder.fromUri(baseUri));

        List<URI>result = mockitoUrl.generateUris();

        for (URI u : result) {
            assertTrue(u instanceof URI);
            System.out.println(u.toString());
        }
    }

}

Когда тест запущен, вывод можно увидеть следующим образом:

generateUris
http://server1/api/system
http://server1/api/system/system
http://server1/api/system/system/system
http://server1/api/system/system/system/system

Я ожидал, что он будет возвращать один и тот же URI каждый раз. В реальном приложении эти URI будут иметь более подробную информацию, и каждый будет иметь разные данные из поиска по классу JPA. Кажется, что один и тот же объект возвращается каждый раз, а затем добавляется снова.

Есть ли способ заставить Mockito возвращать fre sh URI каждый раз, когда вызывается uriInfo.getBaseUriBuilder (), или это у меня есть фундаментальное непонимание того, как работает Mockito?

1 Ответ

0 голосов
/ 28 мая 2020

Проблема, с которой вы сталкиваетесь, - это ожидаемое поведение. При настройке макета вы создаете единственный экземпляр, который всегда возвращается.

Чтобы получить то, что вы хотите, я бы предложил использовать when(..).thenAnswer(i -> UriBuilder.fromUri(baseUri))

Таким образом, каждый вызов выполняет лямбда-выражение, и это создает новый экземпляр для каждого вызова.

...