Как проверить с помощью Mockito, что во время теста был вызван другой общедоступный метод SUT

Мне известно о дубликате, но ответа на конкретный вопрос там не было.

Как проверить, вызывается ли метод в тестируемой системе (не макет)

У меня есть класс:

class A {

    public long a() {
        if (something) {
            return quicklyCalculatedResult
        } else {
            return b() run on separate thread, with this one blocked
        }
    }

    public long b() {} //doStuffOnCurrentThread;

}

У меня есть полный набор тестов для b (), который выполняет тяжелую работу. К сожалению, мне приходится делать уродливую мысль вроде () (устаревший код), и я не хочу копировать все тесты. Метода b (). Кроме того, оба они должны быть общедоступными.

Я хочу убедиться, что при определенных обстоятельствах a () вызывает b (), но я не могу этого сделать, потому что проверенный класс не является имитацией. Мне нужен способ проверить, что метод был вызван для реального объекта, а не только для имитации.

ИМХО, я не думаю, что вам стоит волноваться, если Б. позвонят. Вместо этого сосредоточьтесь на условиях, которые приводят к вызову b (отрицательное значение «something» условного), а затем убедитесь, что вы получили ожидаемые результаты. Смысл насмешек в том, чтобы позволить вам упростить / контролировать вашу зависимость / привязку к классам, которые не тестируются. Кроме того, вам следует, даже если вы не хотите, перенести тесты так, чтобы они сосредоточились на b, но должны сосредоточиться на b.

Jason Armstrong 11.12.2018 12:15

@JasonArmstrong Привет, это способ, но существует множество условий, которые могут привести к вызову b (). В моем реальном примере это больше похоже на «если какой-то аргумент равен нулю, дать быстрый ответ и в любом другом случае получить результат b ()». b () будет отвечать по-разному, в зависимости от заданных аргументов. Итак, чтобы проверить это с возвращенным значением вместо проверки того, был ли вызван b (), мне пришлось бы протестировать несколько сценариев, и это в основном копирование тестов b () ...

Michał Powłoka 11.12.2018 12:25

Я понимаю, о чем вы говорите, но что вы на самом деле единица измерения тестируете в этот момент a или b?

Jason Armstrong 11.12.2018 12:31

Я хочу провести модульное тестирование a (). И требование для a - «если некоторые аргументы равны нулю, тогда что-то вычислите, иначе вызовите b ()».

Michał Powłoka 11.12.2018 12:32

@JasonArmstrong. Хотя я в принципе согласен с тем, что вы говорите, бывают моменты, когда нам приходится тестировать сложный устаревший код. Для этого и было сделано частичное издевательство.

Dean 11.12.2018 12:34

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

Jason Armstrong 11.12.2018 12:39

@JasonArmstrong. Да, вы правы.

Dean 11.12.2018 12:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
1 178
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете сделать A шпионом с помощью @Spy или Mockito.spy(). Это позволит вам вызывать и тестировать логику метода a(), но также заменяет b() инвариантом. Это можно проиллюстрировать списком:

List list = new LinkedList();
List spy = Mockito.spy(list);

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

Спасибо! Это работает, и я проголосовал. Я дал правильный ответ @Dean, потому что его ответ был ближе к вопросу и для вызова .thenCallRealMethod (), но ваш способ тоже работает!

Michał Powłoka 11.12.2018 13:29
Ответ принят как подходящий

Mockito и другие библиотеки имитации kotlin предоставляют частичную имитацию или аналогичные функции. Вы можете указать реальные методы, которые будут вызываться, в то время как другие методы останутся заглушками:

Пример Mockito java:

A classUnderTest = mock(A.class);
when(classUnderTest.a()).thenCallRealMethod();

classUnderTest.a();
verify(classUnderTest).b()

См. Mockito Документация о частичном издевательстве. Частичное имитация не приветствуется, потому что она не соответствует хорошему дизайну ООП, но в вашем случае она соответствует своему прямому назначению, а именно тестированию сложного устаревшего кода.

Пример Kotlin с ванильным Mockito:

val classUnderTest = mock(A::class.java)
`when`(classUnderTest.a()).thenCallRealMethod()

classUnderTest.a()
verify(classUnderTest).b()

мокито-котлин предоставляет расширения, которые позволяют использовать mockito более идиоматическим способом kotlin. К сожалению, не существует способа сделать частичное издевательство идиоматическим способом kotlin, но это может быть достигнуто в mockito-kotlin следующим образом:

val classUnderTest = mock<A>()
doCallRealMethod().whenever(classUnderTest).a()

classUnderTest.a()
verify(classUnderTest).b()

MockK, идиоматическая библиотека имитации котлина, позволяет использовать эту функцию со шпионами. После создания spy класса вы можете выбрать методы-заглушки:

val classUnderTest = spyk<A>()
every { classUnderTest.b() } returns 1L

classUnderTest.a()
verify { classUnderTest.b() }

Привет спасибо! У меня были небольшие проблемы с его работой, но только из-за использования Kotlin вместо Java. Это именно то, что мне было нужно :)

Michał Powłoka 11.12.2018 13:28

Другие вопросы по теме