Подсчет вызовов методов в модульных тестах

#unit-testing #junit4 #mockito #jmockit

#java #модульное тестирование #mockito #junit4 #jmockit ( джмокит ) #jmockit

Вопрос:

Каков наилучший способ подсчета вызовов методов в модульном тестировании. Допускает ли это какая-либо из платформ тестирования?

Комментарии:

1. Не могли бы вы подробнее рассказать о том, что вы пытаетесь сделать? Вы пытаетесь измерить покрытие кода? Производительность? Эффективность?

2. Не совсем. Просто хочу проверить, что когда я вызываю тестовый метод testXXX(), этот метод foo() для класса вызывается не менее N раз.

3. Разве это невозможно? Я знаю, что макетные фреймворки позволяют мне утверждать о количестве вызовов для макетных объектов. Разве это невозможно сделать на реальных объектах?

Ответ №1:

Похоже, вы можете захотеть использовать методы .expects(1) типов, которые обычно предоставляют макетные фреймворки.

Используя mockito, если вы тестировали список и хотели убедиться, что clear вызывался 3 раза, а add вызывался хотя бы один раз с этими параметрами, вы делаете следующее:

 List mock = mock(List.class);        
someCodeThatInteractsWithMock();                 

verify(mock, times(3)).clear();
verify(mock, atLeastOnce()).add(anyObject());      
  

Источник — MockitoVsEasyMock

Ответ №2:

В Mockito вы можете сделать что-то вроде этого:

 YourService serviceMock = Mockito.mock(YourService.class);

// code using YourService

// details of all invocations including methods and arguments
Collection<Invocation> invocations = Mockito.mockingDetails(serviceMock).getInvocations();
// just a number of calls of any mock's methods
int numberOfCalls = invocations.size();
  

Комментарии:

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

2. Спасибо, Якуб, это тоже хорошо, потому что, если вы проверите объект, вы сможете увидеть, где и какие функции вызываются.

3. Это возвращает все вызовы. Должен быть способ получения вызовов одного метода без потоковой передачи и фильтрации этих коллекций и использования отражения для включения Method объекта equal . Подумайте о JS API Sinon: stub.callCount

Ответ №3:

Приведен пример класса «RoleRepository» с единственным методом «getRole (строковый пользователь)», который возвращает роль.

Предположим, вы объявили этот объект как макет или шпионский и хотите проверить, вызывается ли метод getRole(String) один раз за раз.

Вы бы сделали что-то вроде: Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class RoleRepositoryTest {

    @Spy
    private RoleRepository roleRepository = new RoleRepository();

    @Test
    public void test() {
        roleRepository.getRole("toto");
        Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
    }

    public static class RoleRepository {

        public String getRole(String user) {
            return "MyRole";
        }
    }
}
  

Ответ №4:

Вы можете подсчитать количество вызовов методов, используя interface Answer в Mockito.

 ConnectionPool mockedConnectionPool = mock(ConnectionPool.class);

    final int[] counter = new int[1];

    when(mockedConnectionPool.getConnection()).then(new Answer<Connection>() {

        @Override
        public Connection answer(InvocationOnMock invocation) throws Throwable {
            counter[0]  ;
            return conn;
        }

    }); 
    // some your code

    assertTrue(counter[0] == 1);
  

Ответ №5:

В зависимости от того, какие методы вы хотите подсчитать, вы можете создать конфигурацию теста с @Before рекомендациями, соответствующими вашему классу / пакету / методу:

 import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MethodCounterAspect {

    private int counter = 0 // or inject the Counter object into this aspect

    @Pointcut( "execution( * com.sample.your.package.*.*(..) )" )
    public void methodsToCount() {}

    @Before("methodsToCount()")
    public void execute() throws Throwable {
        counter  ; // or update the counter injected into this aspect..
    }

    // get the counter
}
  

Вы можете использовать ванильный AspectJ или Spring AOP через вышеуказанные или XML-конфигурации, если вам так проще.

Вы можете создавать разные точечные вырезы / аспекты, если вам нужно.

Комментарии:

1. Если вы просто хотите посмотреть на количество вызовов, это способ сделать это. Если вы хотите проверить вызовы, макетные фреймворки обычно оборачивают этот шаблон для вас утверждениями. Смотрите Мой ответ для макетной версии.

2. вопрос в том, » Каков наилучший способ подсчета вызовов методов в модульном тестировании «. Вышесказанное позволит вам сделать именно это => подсчитывать вызовы методов в модульных / интеграционных тестах , не загрязняя сами тесты.

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

Ответ №6:

Похоже, вам может понадобиться тестовый шпион. Смотрите, например, Mockito.spy() .

Комментарии:

1. Ссылка Mockito.spy(), похоже, не работает

Ответ №7:

У вас есть несколько вариантов

1) Добавьте какой-нибудь специальный код, который подсчитывает вызовы в функции. Это сработает, но это не самое лучшее решение.

2) После запуска модульных тестов проверьте покрытие кода. Большинство инструментов покрытия будут подсчитывать вызовы, но на самом деле они предназначены для последующей обработки.

3) Используйте профилировщик. Профилировщик позволит вам подсчитать, сколько раз вызывается функция. Это очень ручной процесс, поэтому на самом деле он не предназначен для модульного тестирования.

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