Рубрики
Без рубрики

Как использовать PowerMockito, когда новый

PowerMockito.whennew – это мощная функция для заглушки конструктора. Эта статья продемонстрирует некоторые из них… С тегом powermockito, java.

PowerMockito.whennew – это мощная функция для заглушки конструктора. В этой статье будет продемонстрирован некоторый сценарий, когда мы используем, когда новые и некоторые готы, с которыми я столкнулся по пути.

Допустим, у нас есть два класса: BookDAO и Хранилище книг.

public enum BookDao {

    INSTANCE;

    public String getRecentBookTitle() {
        BookRepository repository = new BookRepository();
        return repository.queryBookTitle();
    }
}

public class BookRepository {

    public String queryBookTitle() {
        return "xUnit Test Patterns";
    }
}

Хранилище книг создается в блоке “Получить последнее название книги”. Как вы тестируете BookDAO.получить последние названия книг()?

@RunWith(PowerMockRunner.class)
@PrepareForTest({BookRepository.class})
public class BookDaoTest {

    @Test
    public void shouldReturnEffectiveJava() throws Exception {
        String bookTitle = BookDao.INSTANCE.getRecentBookTitle();

        // How to verify queryBookTitle?
        // Mockito.verify(mock).queryBookTitle();
    }
}

Идеальное решение – позволить BookDAO изменять свой класс BookRepository с помощью инъекции конструктора или сеттера. Однако давайте предположим, что мы не хотим изменять существующий исходный код. Тем не менее, мы все еще хотим проверить, называется ли название книги запросов.

Вот где мы можем использовать PowerMockito снова. Используя when New, мы можем заглушить создание хранилища книг с помощью макета.

BookRepository mock = Mockito.mock(BookRepository.class);
PowerMockito.whenNew(BookRepository.class).withAnyArguments().thenReturn(mock);

// Verify BookRepository is created
PowerMockito.verifyNew(BookRepository.class).withNoArguments();

Вы даже можете указать аргументы конструктора, используя с аргументами

// Assume BookDao constructor have two arguments
PowerMockito.whenNew(BookRepository.class).withArguments(true, ArgumentMatchers.anyString()).thenReturn(mock);

Как только у нас будет макет хранилища книг, мы сможем многое сделать, в том числе заглушить запрос хранилища книг на возвращаемое значение Названия книги.

// Given
BookRepository mock = Mockito.mock(BookRepository.class);
Mockito.when(mock.queryBookTitle()).thenReturn("Effective Java");
PowerMockito.whenNew(BookRepository.class).withAnyArguments().thenReturn(mock);

// When
String bookTitle = BookDao.INSTANCE.getRecentBookTitle();

// Then
Assert.assertEquals("Effective Java", bookTitle);

Другой вариант использования – захватить аргумент Bookdepository. В этом примере в BookRepository есть новый метод getBookByIsbn, который принимает строку в качестве аргумента.

// Given
String isbn = "978-0134685991";
ArgumentCaptor isbnCaptor = ArgumentCaptor.forClass(String.class);

BookRepository mock = Mockito.mock(BookRepository.class);
PowerMockito.whenNew(BookRepository.class).withNoArguments().thenReturn(mock);

// When
String ignoredBookTitle = BookDao.INSTANCE.getBookByIsbn(isbn);
Mockito.verify(mock).queryBookTitle(isbnCaptor.capture());

// Then
Assert.assertEquals(isbn, isbnCaptor.getValue());

Теперь мы можем проверить, что значение isbn в заголовке книги запросов аналогично тому, что мы передали в BookDAO. Довольно круто, не так ли?

Попался!

Если вы попытаетесь запустить приведенный выше код, вы, скорее всего, столкнетесь с этими ошибками:

  • Желанный, но не вызванный
  • орг.юнит. Ошибка сравнения

Это потому, что нам не удалось отключить хранилище книг. Но почему? Разве мы уже не добавили BookRepository на @preparefortest? Это правда, однако PowerMockito требует, чтобы мы указали класс, который создает Bookdepository, то есть BookDAO. Не само Хранилище Книг.

@RunWith(PowerMockRunner.class)
// You should also add BookDao on PrepareForTest! Even though you didn't mock or stub BookDao class.
@PrepareForTest({BookDao.class})
public class BookDaoTest {

    @Test
    public void shouldReturnEffectiveJava() throws Exception {
       // ...
    }
}

Теперь наш тест весь зеленый.

Резюме

Используя PowerMockito.whennew, мы можем очень легко заглушить конструктор макетом объекта. При этом, дважды подумав о своем текущем дизайне и рефакторинге исходного кода, вы получите гораздо лучшие альтернативы. В конце концов, это одна из причин, по которой мы проводим модульное тестирование, чтобы уменьшить запах кода в нашем коде. Вот полный исходный код этой статьи. Я надеюсь, что вы найдете это полезным.

Я надеюсь, что вы найдете это полезным.

public enum BookDao {

    INSTANCE;

    public String getBookFromCache() {
        BookRepository repository = new BookRepository(true, "http://example.com:4416");
        return repository.queryBookTitle();
    }

    public String getRecentBookTitle() {
        BookRepository repository = new BookRepository();
        return repository.queryBookTitle();
    }

    public String getBookByIsbn(String isbn) {
        BookRepository repository = new BookRepository();
        return repository.queryBookTitle(isbn);
    }

}

Я надеюсь, что вы найдете это полезным.

public class BookRepository {

    // unused variables, for demonstration purpose only
    private boolean useCache;

    private String connectionUrl;

    public BookRepository(boolean useCache, String connectionUrl) {
        this.useCache = useCache;
        this.connectionUrl = connectionUrl;
    }

    public BookRepository() {
        this(false, "");
    }

    public String queryBookTitle(String isbn) {
        return queryBookTitle();
    }

    public String queryBookTitle() {
        return "xUnit Test Patterns";
    }
}

Я надеюсь, что вы найдете это полезным.

import com.aldoapps.mybookshop.BookDao;
import com.aldoapps.mybookshop.BookRepository;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({BookDao.class})
public class BookDaoTest {

    @Test
    public void shouldReturnEffectiveJava1() throws Exception {
        // Given
        BookRepository mock = Mockito.mock(BookRepository.class);
        Mockito.when(mock.queryBookTitle())
               .thenReturn("Effective Java");

        PowerMockito.whenNew(BookRepository.class)
                    .withAnyArguments()
                    .thenReturn(mock);

        // When
        String bookTitle = BookDao.INSTANCE.getRecentBookTitle();

        // Then
        PowerMockito.verifyNew(BookRepository.class)
                    .withNoArguments();

        Assert.assertEquals("Effective Java", bookTitle);
        Mockito.verify(mock)
               .queryBookTitle();
    }

    @Test
    public void shouldReturnEffectiveJava2() throws Exception {
        // Given
        BookRepository mock = Mockito.mock(BookRepository.class);
        Mockito.when(mock.queryBookTitle())
               .thenReturn("Effective Java");

        PowerMockito.whenNew(BookRepository.class)
                    .withArguments(ArgumentMatchers.anyBoolean(),
                            ArgumentMatchers.anyString())
                    .thenReturn(mock);

        // When
        String bookTitle = BookDao.INSTANCE.getBookFromCache();

        // Then
        PowerMockito.verifyNew(BookRepository.class)
                    .withArguments(ArgumentMatchers.anyBoolean(), 
                                   ArgumentMatchers.anyString());

        Assert.assertEquals("Effective Java", bookTitle);
        Mockito.verify(mock)
               .queryBookTitle();
    }

    @Test
    public void shouldHaveSimilarIsbnValue() throws Exception {
        // Given
        String isbn = "978-0134685991";
        ArgumentCaptor isbnCaptor = ArgumentCaptor.forClass(String.class);

        BookRepository mock = Mockito.mock(BookRepository.class);

        PowerMockito.whenNew(BookRepository.class)
                    .withNoArguments()
                    .thenReturn(mock);

        // When
        String ignoredBookTitle = BookDao.INSTANCE.getBookByIsbn(isbn);

        // Then
        PowerMockito.verifyNew(BookRepository.class)
                    .withNoArguments();

        Mockito.verify(mock)
               .queryBookTitle(isbnCaptor.capture());
        Assert.assertEquals(isbn, isbnCaptor.getValue());
    }
}

Оригинал: “https://dev.to/aldok/how-to-use-powermockito-whennew-16m2”