#java #testing #mockito #spy
#java #тестирование #mockito #шпион
Вопрос:
У меня есть класс JUnit с разными методами для выполнения разных тестов.
Я использую Mockito для создания шпиона в реальном экземпляре, а затем переопределяю некоторый метод, который не имеет отношения к фактическому тесту, который я выполняю.
Есть ли способ, просто ради очистки после меня на случай, если некоторые другие тесты, которые выполняются после моих тестов, также используют те же экземпляры и могут выполнить издевательский метод, который они не просили издеваться, отменить издевательство над методом?
допустим, у меня есть шпионский объект с именем ‘wareHouseSpy’
допустим, я переопределил метод ISOMETHINGMISSING :
doReturn(false).when(wareHouseSpy).isSomethingMissing()
Каков будет правильный способ отменить переопределение и вернуть работу шпиона в нормальное состояние, т. е. выполнить следующий вызов isSomethingMissing для запуска реального метода?
что-то вроде
doReturn(Mockito.RETURN_REAL_METHOD).when(wareHouseSpy).isSomethingSpy()
или, может быть
Mockito.unmock(wareHouseSpy)
Кто знает? Я ничего не смог найти в этой области
Спасибо!
Ассаф
Комментарии:
1. «Я использую Mockito для создания шпиона в реальном экземпляре, а затем переопределяю некоторый метод, который не имеет отношения к фактическому тесту, который я выполняю». Я не понимаю, тогда зачем вы издеваетесь над ним, если он вам не нужен?
2. Является ли хранилище в вашем примере одноэлементным или что-то в этом роде? Относятся ли эти «другие тесты» к тому же классу или вы говорите о совершенно другом наборе тестов?
Ответ №1:
Я думаю
Mockito.reset(wareHouseSpy)
сделал бы это.
Комментарии:
1. Это приведет к сбросу всех издеваемых методов. Я думаю, что OP хотел сбросить только один метод (по крайней мере, это то, что я пришел сюда искать :))
2. Ну, я хочу сбросить метод, а затем повторно заглушить этот метод новым значением. Но все равно сохраните
verify(..., times(1))
для этого заглушку метода.
Ответ №2:
Допустим, большинство ваших тестов используют заглушенный ответ. Тогда у вас был бы метод setUp (), который выглядит следующим образом:
@Before
public void setUp() {
wareHouseSpy = spy(realWarehouse);
doReturn(false).when(wareHouseSpy).isSomethingMissing();
}
Теперь предположим, что вы хотите отменить заглушенный ответ и использовать реальную реализацию в одном тесте:
@Test
public void isSomethingMissing_useRealImplementation() {
// Setup
when(wareHouseSpy.isSomethingMissing()).thenCallRealMethod();
// Test - Uses real implementation
boolean result = wareHouseSpy.isSomethingMissing();
}
Комментарии:
1.
.thenCallRealMethod()
помог мне сбросить индивидуальный издевательский метод.2. @Rupesh справился с задачей.
Ответ №3:
Это зависит от того, проводите ли вы тестирование с помощью TestNG или JUnit.
- JUnit создает новый экземпляр самого себя для каждого метода тестирования. В принципе, вам не нужно беспокоиться о сбросе mocks.
- С помощью TestNG вам нужно сбросить макет (ы) с помощью
Mockito.reset(mockA, mockB, ...)
либо в@BeforeMethod
, либо в@AfterMethod
Комментарии:
1. Не правда о JUnit, создающем новый экземпляр для каждого метода. У меня есть один метод, который нарушает работу другого метода, даже несмотря на то, что ВСЕ операции редактирования выполняются для каждого метода.
2. @AgilePro В 2011 году был только JUnit 4, и в его FAQ упоминается » Он выполняет каждый тест в отдельном экземпляре тестового класса «. Другие писали на ту же тему: Жизненный цикл тестового класса . И это также используется по умолчанию в JUnit 5 , см. Жизненный цикл экземпляра теста : » … для выполнения изолированно … JUnit создает новый экземпляр каждого тестового класса перед выполнением каждого тестового метода «.
Ответ №4:
«Обычный» способ заключается в повторном создании экземпляров в вашем методе «setUp». Однако, если у вас есть реальный объект, создание которого по какой-либо причине обходится дорого, вы могли бы сделать что-то вроде этого:
public class MyTests {
private static MyBigWarehouse realWarehouse = new MyBigWarehouse();
private MyBigWarehouse warehouseSpy;
@Before
public void setUp() {
warehouseSpy = spy(realWarehouse); // same real object - brand new spy!
doReturn(false).when(wareHouseSpy).isSomethingMissing();
}
@Test
...
@Test
...
@Test
...
}
Комментарии:
1. Если вы не объявите realWarehouse как статическую переменную, она будет создаваться заново для каждого теста.
2. Вы правы. Я изменил ответ, чтобы отразить это.
Ответ №5:
Может быть, я не понимаю, но когда у вас есть реальный объект real
:
Object mySpy = spy(real);
Затем «отменить слежку» mySpy
… просто используйте real
.
Ответ №6:
Согласно документации, у нас есть
reset(mock);
//at this point the mock forgot any interactions amp; stubbing
В документации указано дальнейшее
Обычно вам не нужно сбрасывать свои mocks, просто создайте новые mocks для каждого метода тестирования. Вместо #reset(), пожалуйста, рассмотрите возможность написания простых, небольших и целенаправленных методов тестирования с использованием длительных, чрезмерно заданных тестов.
Вот пример из их репозитория github, который тестирует это поведение и использует его:
@Test
public void shouldRemoveAllInteractions() throws Exception {
mock.simpleMethod(1);
reset(mock);
verifyZeroInteractions(mock);
}
ссылка : ResetTest.java
Ответ №7:
Обращаясь конкретно к этому фрагменту:
Есть ли способ, просто ради очистки после меня на случай, если некоторые другие тесты, которые выполняются после моих тестов, также используют те же экземпляры и могут выполнить издевательский метод, который они не просили издеваться, отменить издевательство над методом?
Если вы используете JUnit, самый простой способ сделать это — использовать @Before
и @After
(другие фреймворки имеют эквиваленты) и воссоздать экземпляр и шпион, чтобы ни один тест не зависел от того, что вы сделали в любом другом тесте, или на него не повлияло то, что вы сделали в любом другом тесте. Затем вы можете выполнить специфичную для теста конфигурацию spy / mock внутри каждого теста. Если по какой-то причине вы не хотите воссоздавать объект, вы можете воссоздать шпион. В любом случае, каждый раз все начинают с нового шпиона.