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

Как лучше всего подсчитать вызовы методов в модульном тесте. Любая из сред тестирования позволяет это?


person user855    schedule 08.10.2011    source источник
comment
Не могли бы вы уточнить, что вы пытаетесь сделать? Вы пытаетесь измерить покрытие кода? Производительность? Эффективность?   -  person Mark Robinson    schedule 08.10.2011
comment
Не совсем. Просто хочу проверить, что когда я вызываю тестовый метод testXXX(), этот метод foo() в классе вызывается как минимум N раз.   -  person user855    schedule 08.10.2011
comment
Разве это невозможно? Я знаю, что фреймворки Mocking позволяют мне утверждать количество вызовов для объектов Mock. Разве нельзя это сделать на реальных объектах?   -  person user855    schedule 08.10.2011


Ответы (7)


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

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

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

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

Источник – MockitoVsEasyMock.

person case nelson    schedule 08.10.2011

В 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();
person Jakub Kubrynski    schedule 13.08.2016
comment
Я обнаружил, что это самый простой и эффективный метод, когда у вас есть доступ к издевательскому объекту. - person iZian; 07.09.2017
comment
Спасибо, Якуб, это тоже хорошо, потому что если вы осмотрите объект, вы увидите, где и какие функции вызываются. - person Stoffe; 09.03.2018
comment
Это получает все вызовы. Должен быть способ получить вызовы одного метода без потоковой передачи и фильтрации этих коллекций и использования Reflection для получения объекта Method для equal. Вспомните JS API Синон: stub.callCount - person oligofren; 27.06.2018

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

Предположим, вы объявили этот объект как Mock или Spy и хотите проверить, вызывается ли метод 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";
        }
    }
}
person OlivierTerrien    schedule 25.01.2018

Вы можете подсчитать количество вызовов метода, используя интерфейс 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);
person oleh.kovaliuk    schedule 27.12.2013

В зависимости от того, какие методы вы хотите посчитать, вы можете создать тестовую конфигурацию с советом @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
}

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

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

person tolitius    schedule 08.10.2011
comment
Если вы просто хотите посмотреть на количество вызовов, это способ сделать это. Если вы хотите проверить вызовы, фиктивные фреймворки обычно обертывают этот шаблон утверждениями. Смотрите мой ответ для фиктивной версии. - person case nelson; 08.10.2011
comment
вопрос заключается в следующем: Как лучше всего подсчитывать вызовы методов в модульном тесте. Вышеупомянутое позволит вам сделать именно это =› количество вызовов методов в модульных / интеграционных тестах, не загрязняя сами тесты. - person tolitius; 08.10.2011
comment
Я согласен, поэтому я проголосовал за вас. Но в комментариях автор спрашивает об утверждении количества вызовов для реальных объектов по сравнению с фиктивными объектами. Если он хочет на самом деле протестировать вызовы, ему следует использовать фиктивную библиотеку, потому что именно для этого они созданы. - person case nelson; 08.10.2011

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

person Michael Brewer-Davis    schedule 08.10.2011
comment
Ссылка Mockito.spy() кажется неработающей - person Samarth S; 28.05.2020

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

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

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

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

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

person Mark Robinson    schedule 08.10.2011