it-swarm.com.ru

Мокито - шпион против насмешки

Mockito - я понимаю, что шпион вызывает реальные методы для объекта, в то время как mock вызывает методы для двойного объекта. Также следует избегать шпионов, если не ощущается запах кода .. Однако, как работают шпионы и когда мне на самом деле их использовать? Чем они отличаются от ложных?

53
Abhinav

Технически говоря, и «шутки», и «шпионы» - это особый вид «двойников».

Мокито, к сожалению, делает это различие странным.

Макет в mockito - это обычный макет в других инфраструктурах mocking (позволяет заглушить вызовы; то есть возвращать конкретные значения из вызовов методов).

Шпион в mockito - это частичная имитация в других фреймворках (часть объекта будет смоделирована, а часть будет использовать реальные вызовы методов).

60
Crazyjavahacking

Я создал работоспособный пример здесь https://www.surasint.com/mockito-with-spy/

Я копирую часть этого здесь. 

Если у вас есть что-то вроде этого кода:

public void transfer( DepositMoneyService depositMoneyService, 
                      WithdrawMoneyService withdrawMoneyService, 
                      double amount, String fromAccount, String toAccount) {
    withdrawMoneyService.withdraw(fromAccount,amount);
    depositMoneyService.deposit(toAccount,amount);
}

Вам может не понадобиться шпион, потому что вы можете просто издеваться над DepositMoneyService и WithdrawMoneyService.

Но с некоторым унаследованным кодом зависимость находится в коде так:

    public void transfer(String fromAccount, String toAccount, double amount) {
        this.depositeMoneyService = new DepositMoneyService();
        this.withdrawMoneyService = new WithdrawMoneyService();
        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }

Да, вы можете перейти к первому коду, но затем API будет изменен. Если этот метод используется во многих местах, вы должны изменить их все.

Альтернативой является то, что вы можете извлечь зависимость следующим образом:

    public void transfer(String fromAccount, String toAccount, double amount){
        this.depositeMoneyService = proxyDepositMoneyServiceCreator();
        this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator();
        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }

    DepositMoneyService proxyDepositMoneyServiceCreator() {
        return new DepositMoneyService();
    }

    WithdrawMoneyService proxyWithdrawMoneyServiceCreator() {
        return new WithdrawMoneyService();
    }

Затем вы можете использовать шпион для вставки зависимости следующим образом:

DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class);
        WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class);

    TransferMoneyService target = spy(new TransferMoneyService());

    doReturn(mockDepositMoneyService)
            .when(target)
            .proxyDepositMoneyServiceCreator();

    doReturn(mockWithdrawMoneyService)
            .when(target)
            .proxyWithdrawMoneyServiceCreator();

Более подробно в ссылке выше.

11
Surasin Tancharoen

TL; версия DR,

С mock , он создаст для вас экземпляр Shell.

List<String> mockList = Mockito.mock(ArrayList.class);

С шпион вы можете частично издеваться над существующим экземпляром

List<String> spyList = Mockito.spy(new ArrayList<String>());

Типичный вариант использования Spy: у класса есть параметризованный конструктор, вы хотите сначала создать объект.

9
del bao

Лучшее место для начала, вероятно, документы для mockito .

На общей ноте макет mockito позволяет создавать заглушки. 

Вы бы создали метод-заглушку, если, например, этот метод выполняет дорогостоящую операцию. Скажем, он получает соединение с базой данных, получает значение из базы данных и возвращает его вызывающей стороне. Получение соединения с БД может занять 30 секунд, замедляя выполнение теста до точки, где вы, вероятно, переключите контекст (или прекратите выполнение теста). 

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

Шпион mockito позволяет проверить, вызывает ли метод другие методы. Это может быть очень полезно при попытке тестировать устаревший код.

Полезно, если вы тестируете метод, который работает через побочные эффекты, тогда вы бы использовали шпион-мокито. Это делегирует вызовы к реальному объекту и позволяет вам проверять вызов метода, количество вызовов и т.д.

9
Jaimie Whiteside

Оба могут быть использованы для макета методов или полей. Разница в том, что в макете вы создаете полный фиктивный или фальшивый объект, в то время как в шпионе есть реальный объект, и вы просто подглядываете или заглушаете его конкретными методами.

Конечно, в шпионских объектах, поскольку это реальный метод, когда вы не заглушаете метод, он вызывает реальное поведение метода. Если вы хотите изменить и смоделировать метод, вам нужно его заглушить.

Рассмотрим приведенный ниже пример в качестве сравнения.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
 
import Java.util.ArrayList;
import Java.util.List;
 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
 
@RunWith(MockitoJUnitRunner.class)
public class MockSpy {
 
    @Mock
    private List<String> mockList;
 
    @Spy
    private List<String> spyList = new ArrayList();
 
    @Test
    public void testMockList() {
        //by default, calling the methods of mock object will do nothing
        mockList.add("test");

        Mockito.verify(mockList).add("test");
        assertEquals(0, mockList.size());
        assertNull(mockList.get(0));
    }
 
    @Test
    public void testSpyList() {
        //spy object will call the real method when not stub
        spyList.add("test");

        Mockito.verify(spyList).add("test");
        assertEquals(1, spyList.size());
        assertEquals("test", spyList.get(0));
    }
 
    @Test
    public void testMockWithStub() {
        //try stubbing a method
        String expected = "Mock 100";
        when(mockList.get(100)).thenReturn(expected);
 
        assertEquals(expected, mockList.get(100));
    }
 
    @Test
    public void testSpyWithStub() {
        //stubbing a spy method will result the same as the mock object
        String expected = "Spy 100";
        //take note of using doReturn instead of when
        doReturn(expected).when(spyList).get(100);
 
        assertEquals(expected, spyList.get(100));
    }
}

Когда ты используешь шутку или шпион? Если вы хотите быть в безопасности и избегать вызова внешних служб и просто хотите проверить логику внутри устройства, используйте mock. Если вы хотите вызвать внешнюю службу и выполнить вызов реальной зависимости или просто сказать, что хотите запустить программу как есть и просто заглушить определенные методы, используйте spy. Так вот в чем разница между шпионом и издевательством в мокито.

8
Vu Truong

Мне нравится простота этой рекомендации:

  • Если вы хотите быть в безопасности и избегать вызова внешних служб и просто хотите проверить логику внутри устройства, используйте mock.
  • Если вы хотите вызвать внешнюю службу и выполнить вызов реальных зависимостей или просто сказать, что хотите запустить программу как есть и просто заглушить определенные методы, используйте spy.

Источник: https://javapointers.com/tutorial/difference-between-spy-and-mock-in-mockito/

1
leo9r

Вы можете следовать ниже URL-адресу блога, где его сравнивают с нижеуказанными точками:

  1. Объявление объекта
  2. Когда методы не издеваются
  3. Когда метод издевается

https://onlyfullstack.blogspot.com/2019/02/mockito-mock-vs-spy.html URL основного учебника - https://onlyfullstack.blogspot.com/2019/02/mockito-tutorial .html

0
Saurabh Oza