Всем привет, мы снова встретились, я ваш друг Цюаньчжаньцзюнь.
AndroidединицатестВ основном делятся на следующие два типа
на При создании нового проекта в Android Studio,app
изgradle
будет добавлен по умолчаниюединицатестиз Связанные зависимости Библиотека:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }
вtestImplementation
добавить виз Зависимостьместныйизменятьтест Библиотека, androidTestImplementation
Добавленная зависимость — это тестовая библиотека в среде Android. При этом в каталоге проекта по умолчанию будет создана тестовая директория:
вapp/src/test/
Магазин нижеиздаJunitместныйтесткод,app/src/androidTest/
Магазин нижеиздаAndroidтесткод。
Чтобы провести локальное модульное тестирование, вам необходимо сначала понять некоторые основные аннотации Junit:
Название аннотации | значение |
---|---|
@Test | Определенный метод является методом модульного тестирования, и этот метод должен быть общедоступным и недействительным. |
@Before | Определенный метод выполняется один раз перед выполнением каждого тестового примера и используется для подготовки тестовой среды (например, инициализации класса, чтения входного потока и т. д.). В тестовом классе будет выполняться каждый метод @Test. вызвать звонок. |
@After | Определенный метод выполняется один раз после выполнения каждого тестового примера для очистки данных тестовой среды. В тестовом классе выполнение каждого метода @Test вызывает вызов. |
@BeforeClass | Определенный метод запускается один раз перед запуском всех вариантов использования в тестовом классе. Метод должен быть public static void, который используется для выполнения некоторых трудоемких работ по инициализации (например, подключения к базе данных). |
@AfterClass | Определенный метод запускается один раз после выполнения всех вариантов использования в тестовом классе. Метод должен быть public static void, который используется для очистки данных (например: отключение подключений к данным). |
@Test (expected = Exception.class) | Если метод тестирования не выдает тип Exception в аннотации (подклассы также приемлемы), тест не пройден. |
@Test(timeout=100) | Если метод тестирования занимает более 100 миллисекунд, тест не пройден и используется для тестирования производительности. |
@Ignore или @Ignore («слишком много времени») | Игнорировать текущий метод тестирования. Обычно он используется, когда метод тестирования не готов или требует слишком много времени. |
@FixMethodOrder | Все тестовые методы в тестовом классе, в котором находится определение, выполняются в фиксированном порядке. Вы можете указать 3 значения, а именно DEFAULT, JVM, NAME_ASCENDING (в алфавитном порядке). |
@RunWith | Укажите исполнителя тестов для класса тестов. |
Для получения дополнительной информации см.JunitОфициальный сайт:https://junit.org/junit4/
Далее вы можете создать тестдобрый,Помимо создания вручную тестадобрый,можно использоватьASбыстрая клавиша:Выберите курсор для созданиятестдобрыйиздобрыйпо имени->нажиматьALT + ENTER->существоватьнеожиданно возникнутьиз Выберите во всплывающем окнеCreate Test
Появится следующее всплывающее окно, или щелкните правой кнопкой мыши имя класса и выберите «Перейти» в меню. to–>Test,Также появится следующее всплывающее окно
Отметьте метод, который необходимо протестировать, и автоматически сгенерируется тестовый класс:
Если отмечено@Before
или@After
из Он также автоматически сгенерирует для вас соответствующий ответ.изтестметод
Затем напишите тестовый метод. Сначала напишите несколько бизнес-методов в целевом классе, который будет тестироваться:
public class SimpleClass { public boolean isTeenager(int age) { if (age < 15) { return true; } return false; } public int add(int a, int b) { return a + b; } public String getNameById(int id) { if (id == 1) { return «Сяо Мин»; } else if (id == 2){ return «Красненькая»; } return ""; } }
Затем тестовый класс:
@RunWith(JUnit4.class) public class SimpleClassTest { private SimpleClass simpleClass; @Before public void setUp() throws Exception { simpleClass = new SimpleClass(); } @After public void tearDown() throws Exception { } @Test public void isTeenager() { Assert.assertFalse(simpleClass.isTeenager(20)); Assert.assertTrue(simpleClass.isTeenager(14)); } @Test public void add() { Assert.assertEquals(simpleClass.add(3, 2), 5); Assert.assertNotEquals(simpleClass.add(3, 2), 4); } @Test public void getNameById() { Assert.assertEquals(simpleClass.getNameById(1), «Сяо Мин»); Assert.assertEquals(simpleClass.getNameById(2), «Красный»); Assert.assertEquals(simpleClass.getNameById(10), ""); } }
вsetUp()
да自动генерироватьиздобавить в了@Before
аннотация,Это будет выполняться перед каждым выполнением тестового метода.,Поэтому существование создает здесь целевой объект,Вы также можете добавить@BeforeClass
аннотация Но в это времяsetUp()
должен Изменить настатическийизметод。Затемсуществоватькаждыйтестметод Подготовлено втествариант использования,здесьиспользоватьorg.junit.Assert
В сумкеизутверждениеметод,Есть многоassertXXX
метод,Вы можете решить, соответствуют ли результаты целевого метода ожиданиям.
метод | значение |
---|---|
assertNull(Object object) | Объект утверждения пуст |
assertNull(String message, Object object) | Объект утверждения пусто, если оно не пусто, будет выдано исключение, содержащее указанную информацию о сообщении. |
assertNotNull(Object object) | Утвердить, что объект не пуст |
assertNotNull(Object object) | Утвердить, что объект не пусто, если оно пусто, будет создано исключение, содержащее указанную информацию о сообщении. |
assertSame(Object expected, Object actual) | Утвердить, что два объекта относятся к одному и тому же объекту |
assertSame(String message, Object expected, Object actual) | Утвердить, что два объекта относятся к одному и тому же объекту, в противном случае будет выдано исключение с указанной информацией о сообщении. |
assertNotSame(Object expected, Object actual) | Утвердить, что два объекта не ссылаются на один и тот же объект. |
assertNotSame(String message, Object expected, Object actual) | Утвердить, что два объекта не ссылаются на один и тот же объект.,В противном случае генерируется исключение, содержащее указанную информацию о сообщении. |
assertTrue(boolean condition) | Утверждать, что результат верен |
assertTrue(String message, boolean condition) | Утверждать, что результат верен, Если значение false, генерируется исключение, содержащее указанную информацию о сообщении. |
assertFalse(boolean condition) | Утверждать, что результат неверен |
assertFalse(String message, boolean condition) | Утверждать, что результат неверен, Если это правда, генерируется исключение, содержащее указанную информацию о сообщении. |
assertEquals(long expected, long actual) | Утверждать, что значения двух длинных типов ожидаемого и фактического равны |
assertEquals(String message, long expected, long actual) | Утверждать, что значения двух длинных типов ожидаемого и фактического равным образом, если не равно, будет выброшено исключение, несущее указанную информацию о сообщении. |
assertEquals(Object expected, Object actual) | Утверждать, что два объекта равны |
assertEquals(String message, Object expected, Object actual) | Утверждать, что два объекта равным образом, если не равно, будет выдано исключение, несущее указанную информацию о сообщении. |
assertEquals(float expected, float actual, float delta) | утверждать два float тип expect и actual существовать delta Величина отклонения равна, дельта – погрешность ошибки. |
assertEquals(String message, float expected, float actual, float delta) | утверждать два float тип expect и actual существовать delta Значение отклонения равно, если не равно, будет выдано исключение, несущее указанную информацию сообщения. |
assertEquals(double expected, double actual, double delta) | утверждать два double тип expect и actual существовать delta Равно ниже значения отклонения |
assertEquals(String message, double expected,double actual, double delta) | утверждать два double тип expect и actual существовать delta Значение отклонения равно, если не равно, будет выдано исключение, несущее указанную информацию сообщения. |
assertArrayEquals(T[] expected, T[] actual) | утверждать два Элементы одного и того же массива равны во взаимно однозначном соответствии |
assertArrayEquals(String message, T[] expected, T[] actual) | утверждать два Элементы одного и того же массива равны во взаимно однозначном соответствии,Если они не равны, будет выдано исключение, несущее указанную информацию о сообщении. |
fail() | Просто сделай так, чтобы тест провалился |
fail(String message) | Просто сделай так, чтобы тест провалился и выдал сообщение об ошибке |
assertThat(T actual, Matcher<? super T> matcher) | Утвердить, что фактические правила сопоставления совпадают |
assertThat(String reason, T actual, Matcher<? super T> matcher) | Утвердить, что фактические правила сопоставления совпадают,В противном случае генерируется исключение, содержащее указанную информацию о причине. |
вassertEquals
изметод,Каждый соответствует одномуassertNotEquals
метод,Здесь не указано,assertThat
да一个强大изметод:
Assert.assertThat(1, is(1)); Assert.assertThat(0, is(not(1))); Assert.assertThat("hello", startsWith("h")); List<String> items = new ArrayList<>(); items.add("aaa"); items.add("bbb"); Assert.assertThat(items, hasItem("aaa"));
Требуется статический импортorg.hamcrest.Matchers
добрыйвизметод,Чтобы узнать больше о методе сопоставления, обратитесь к этому доброму.
Выберите класс теста, нажмите правой кнопкой мыши «Выполнить», и результаты теста отобразятся на панели управления:
Если все тестовые сценарии нормально возвращают ожидаемые результаты,Тогда перед каждым тестметодом в левой части панели появится зеленая галочка.,в противном случаеметодпревратится в красный восклицательный знак и панель управлениявыходаномальный,Теперь попробуем изменить бизнес-метод:
public boolean isTeenager(int age) { if (age < 15) { return false; } return false; }
Здесь будетage < 15
Изменить навыходfalse,Предположим, что это вызвано небрежностью при кодировании.,Затембегать Тестовый класс:
Панель управления сообщит вам, в какой строке ошибка:
Другими словами, здесь не возвращаются ожидаемые результаты, а значит, написанная нами бизнес-логика неверна, и ошибку необходимо исправить.
Выше весь тестдобрый бег,Если вы хотите запустить один метод тестадобрый,Тогда мышь лишь выбирает для запуска определенный тестовый метод.,Затем щелкните правой кнопкой мыши и выберите «Выполнить». Если вы хотите запустить несколько тестов одновременно,И если в одном пакете имеется несколько тестдобрыйсуществовать,Затем выберите каталог пакета из нескольких тестдобрыйсуществовать.,Затем щелкните правой кнопкой мыши и выберите «Выполнить». В противном случае его можно указать следующим образом,Создать пустой тестдобрый,Затем добавьте аннотации:
@RunWith(Suite.class) @Suite.SuiteClasses({SimpleClassTest.class, SimpleClass2Test.class}) public class RunMultiTest { }
Запуск этого тестдоброго запустит указанный тестдобрый вместе с методом.
Представленные ранее варианты использования позволяют тестировать только варианты использования кода Java, не задействующие API-интерфейсы, связанные с Android. Это неудобно, если задействованы API-интерфейсы, связанные с Android. В настоящее время, если вы не полагаетесь на сторонние библиотеки, вам могут понадобиться. использовать инструментированное тестирование для запуска на устройствах Android. Run, поэтому есть несколько лучших сторонних альтернативных фреймворков, которые могут имитировать тестирование кода с использованием Android. Mockito — это фреймворк тестирования, основанный на внедрении зависимостей.
Что такое Мок, Китайское значение этого слова — «имитация» или «ложь», что означает имитация объекта. Зачем подражать? В традиционном модуле тестирования JUnit зависимость от объектов в существованиитеста не устраняется, например, объект A зависит от метода объекта B, с Когда уществоватьтест объекта А, нам необходимо сконструировать объект Б, что увеличивает сложность теста и делает невозможным реализацию какого-либо доброго теста. Это противоречит идее юнит-теста. Другая серьезная проблема заключается в том, что локальный модульный тест не может полагаться на Android API, поскольку он запускает локальную среду JVM. Трудно смоделировать полную среду Android, полагаясь только на чистую тестовую среду JUnit, что приводит к невозможности тестирования Android. связанный код и Mock. Чтобы решить эту проблему, симуляцию объекта можно легко реализовать с помощью Mock.
Добавьте зависимости:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) testImplementation 'org.mockito:mockito-core:2.19.0' .... }
Перед использованием удобнее импортировать статически:
// Статический импорт делает код чище import static org.mockito.Mockito.*;
Непосредственно издеваться над объектом:
@Test public void testMock() { SimpleClass mockSimple = Mockito.mock(SimpleClass.class); assertNotNull(mockSimple); }
Метод аннотации имитирует объект:
@Mock SimpleClass simple; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testMock() { assertNotNull(simple); }
Режим бегуна имитирует объект:
@RunWith(MockitoJUnitRunner.class) public class ExampleUnitTest { @Mock SimpleClass simple; @Test public void testMock() { assertNotNull(simple); } }
Метод MockitoRule имитирует объект:
public class ExampleUnitTest { @Mock SimpleClass simple; @Rule //<--использовать@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @Test public void testMock() { assertNotNull(simple); } }
verify(T mock)
из作用дапроверять发生из Некоторые действия эквивалентныverify(mock, times(1))
Например:
@Test public void testMock() { //Создаем фиктивный объект List mockedList = mock(List.class); //Используем фиктивный объект mockedList.add("one"); mockedList.clear(); //Проверяем, вызывается ли методockedList.add("one"). Если он вызывается, текущий тест-метод проходит успешно, в противном случае он завершается неудачно. verify(mockedList).add("one"); //проверять Вызывается ли методockedList.clear(), если он вызывается, текущий тест-метод проходит, в противном случае он терпит неудачу. verify(mockedList).clear(); }
@Test public void testMock() { mock.someMethod("some arg"); //проверятьmock.someMethod("some arg") вызывается, если он вызывается, тестметод проходит успешно, в противном случае он терпит неудачу. verify(mock).someMethod("some arg"); }
То есть, если вы закомментируете вызывающий метод, запуск метода testMock() завершится неудачей.
проходитьverify
Ключевые слова,После создания макета объекта,Макетный объект запоминает все взаимодействия. Затем вы можете выборочно проверять взаимодействия, которые вас интересуют.
Обычно необходимо сотрудничать с каким-либо тестовым методом для проверки определенного поведения.,Этот метод называется «Заглушки».,Укладка означает выполнение некоторых операций моделирования над имитируемыми объектами.,Например, установка возвращаемого значения моделирования или выдача исключения и т. д.
Распространенный метод укладки:
методимя | методзначение |
---|---|
doReturn(Object toBeReturned) | Задайте значение, которое будет возвращено заранее |
doThrow(Throwable… toBeThrown) | Установите исключения, которые будут выброшены заранее |
doAnswer(Answer answer) | Перехватите результаты заранее |
doCallRealMethod() | Вызвать реальную реализацию определенного метода |
doNothing() | Установка функции void ничего не дает |
thenReturn(T value) | Установите значение, которое будет возвращено |
thenThrow(Throwable… throwables) | Установите исключение, которое будет выброшено |
thenAnswer(Answer<?> answer) | Перехватить результаты |
Например:
@Test public void testMock() { // Вы можете имитировать определенные функции, а не только интерфейсы. List mockedList = mock(List.class); // Забивка свай when(mockedList.get(0)).thenReturn("first"); doReturn("aaaa").when(mockedList).get(1); when(mockedList.get(1)).thenThrow(new RuntimeException()); doThrow(new RuntimeException()).when(mockedList).clear(); // Вывод «первый» System.out.println(mockedList.get(0)); // Потому что получить(999) Нагромождения нет, поэтому результат равен нулю, Обратите внимание, что в среде моделирования в этом месте не будет сообщаться об исключении IndexOutOfBoundsException. System.out.println(mockedList.get(999)); // Исключение будет выброшено, когда get(1) System.out.println(mockedList.get(1)); // очистить выдаст исключение mockedList.clear(); }
doXXX
иthenXXX
использоватьначальствопочти,Один из них — установить возвращаемое значение перед вызовом метода.,Один из них — установить возвращаемое значение после вызова метода в существующем состоянии. По умолчанию,Все непустые функции макетируемых объектов имеют возвращаемые значения.,Возвращаемое значение по умолчанию для типа объекта равно нулю.,Например возвратint、boolean、String
изфункция,Возвращаемые значения по умолчанию:0、false
иnull
。
when(T methodCall)
функциябитькучаметод Нужно сотрудничатьwhen(T methodCall)
функция,Это значит сделать метод тестовой сваи эффективным. Если вы хотите, чтобы этот макет вызывал определенный метод и возвращал определенное значение,Тогда вы можете использовать его.
Например:
when(mock.someMethod()).thenReturn(10); //Вы можете использовать гибкое сопоставление параметров, например when(mock.someMethod(anyString())).thenReturn(10); //Устанавливаем выброшенное исключение when(mock.someMethod("some arg")).thenThrow(new RuntimeException()); //Не могли бы выкдля разных эффектовиз Непрерывные обратные вызовыизметод Забивка свай: //Последняя тестовая стопка (Пример: возвращает объект: «foo») определяет следующий метод обратного вызова и его поведение. when(mock.someMethod("some arg")) .thenReturn("foo")//Сначала вызываем someMethod("some arg") вернет "foo" .thenThrow(new RuntimeException());//Вызов someMethod("some второй раз arg") вызовет исключение //Вы можете использовать следующий метод, чтобы заменить уменьшенную версию связной тестовой стопки: when(mock.someMethod("some arg")) .thenReturn("one", "two"); //и Следующий метод имеет тот же эффект when(mock.someMethod("some arg")) .thenReturn("one") .thenReturn("two"); //Сравниваем меньшую версию связной тестовой стопки и выдаем исключение: when(mock.someMethod("some arg")) .thenThrow(new RuntimeException(), new NullPointerException();
thenAnswer
сделать обратный звоноктесткучаwhen(mock.someMethod(anyString())).thenAnswer(new Answer() { Object answer(InvocationOnMock invocation) { Object[] args = invocation.getArguments(); Object mock = invocation.getMock(); return "called with arguments: " + args; } }); // выход : "called with arguments: foo" System.out.println(mock.someMethod("foo"));
doCallRealMethod()
функция Приходитьпозвонитьметодизреальная реализацияметодУведомление,существоватьMockсреда,Все объекты моделируются.,Результаты метода также необходимо смоделировать.,Если вы не задали результат симуляции для имитируемого объекта,вернет значение по умолчанию,Например:
public class Person { public String getName() { return «Сяо Мин»; } } @Test public void testPerson() { Person mock = mock(Person.class); //выходnull,Если не установлено обратное значение макета, когда(mock.getName()).thenReturn("xxx"); System.out.println(mock.getName() }
Поскольку метод getName() не устанавливает моделируемое возвращаемое значение.,Возвращаемое значение getName() — тип String.,Таким образом, прямой вызов вернет значение String по умолчанию, равное нулю.,Местокначальстволапшакод Если ты хочешьвыходgetName()методизреальная возвращаемая стоимостьизразговаривать,Необходимо установить doCallRealMethod():
@Test public void testPerson() { Person mock = mock(Person.class); doCallRealMethod().when(mock).getName(); //выход“Сяо Мин” System.out.println(mock.getName()); }
doNothing()
функция предназначена для Установка функции void ничего не даетнуждаться Уведомлениеизда По умолчанию返回值为voidизфункциясуществоватьmocksсерединада什么也不做из但да,Будут также некоторые особые обстоятельства. нравиться:
Когда тестовая заглушка постоянно вызывает функцию void:
doNothing().doThrow(new RuntimeException()).when(mock).someVoidMethod(); //does nothing the first time: mock.someVoidMethod(); //throws RuntimeException the next time: mock.someVoidMethod();
Отслеживайте реальные объекты, и вы хотите, чтобы функция void ничего не делала:
List list = new LinkedList(); List spy = spy(list); //let's make clear() do nothing doNothing().when(spy).clear(); spy.add("one"); //clear() does nothing, so the list still contains "one" spy.clear();
doAnswer()
функцияфункция testvoidизперезвонитьЕсли вы хотите использовать функцию, которая не возвращает значения,Вы можете использовать функцию doAnswer() с общим параметром добрыйAnswer в качестве теста обратного вызова. Предположим, у вас есть метод void с несколькими параметрами обратного вызова.,Если вы хотите указать обратный вызов для выполнения,Трудно реализовать с помощью thenAnswer,Это будет очень просто, если вы используете doAnswer().,Пример кода выглядит следующим образом:
MyCallback callback = mock(MyCallback.class); Mockito.doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { //Получаем первый параметр MyCallback call = invocation.getArgument(0); //Указываем обратный вызов для выполнения операции call.onSuccess(); return null; } }).when(mockedObject.requset(callback)); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { System.out.println("onSuccess answer"); return null; } }).when(callback).onSuccess(); mockedObject.requset(callback)
Например, при мониторинге реальных объектов и влиянии вызова реальных функций
List list = new LinkedList(); List spy = spy(list); //Невозможно: список все еще пуст, когда вызывается реальный метод, поэтому spy.get(0) выдаст исключение IndexOutOfBoundsException() when(spy.get(0)).thenReturn("foo"); //В это время вам следует использовать функцию doReturn() doReturn("foo").when(spy).get(0);
doThrow()
функция Приходитьфункция testvoidБросатьаномальныйSimpleClass mock = mock(SimpleClass.class); doThrow(new RuntimeException()).when(mock).someVoidMethod(); mock.someVoidMethod();
СуммируяиспользоватьdoThrow(), doAnswer(), doNothing(), doReturn() and doCallRealMethod()
Этифункция Когда можноксуществоватьподходящийкогдаиз Звоню на всякий случайwhen()
решить некоторые проблемы., Это необходимо, когда вам нужны следующие функции:
Нужно использовать какой-то метод
метод | значение |
---|---|
times(int wantedNumberOfInvocations) | Проверьте количество вызовов метода |
never() | Убедитесь, что взаимодействие не произошло, что эквивалентно times(0) |
only() | Убедитесь, что метод вызывается только один раз.,Эквивалентно раз(1) |
atLeast(int minNumberOfInvocations) | Проверьте не менее n раз |
atMost(int maxNumberOfInvocations) | Подтверждайте не более n раз |
after(long millis) | существуют Подтвердить через заданное время |
timeout(long millis) | Проверьте, истекло ли время выполнения метода. |
description(String description) | Вывод контента при неудачной проверке |
verifyZeroInteractions | Убедитесь, что фиктивный объект не взаимодействует. |
Например:
mock.someMethod("some arg"); mock.someMethod("some arg"); //проверятьmock.someMethod("some arg") вызывается дважды подряд, то есть, если он не вызывается дважды, проверка не удалась. verify(mock, times(2)).someMethod("some arg");
//Уведомление,Следующие три эквивалентны,Все проверяют, что someMethod() вызывается только один раз. someMethod("некоторый аргумент");
mPerson.getAge(); mPerson.getAge(); //проверять вызывается минимум 2 раза verify(mPerson, atLeast(2)).getAge(); //проверять можно вызвать не более 2 раз verify(mPerson, atMost(2)).getAge();
//Следующие два эквивалентны,Количество вызовов проверки равно 0verify(mPerson, Never()).getAge();verify(mPerson, times(0)).getAge();
mPerson.getAge(); mPerson.getAge(); long current = System.currentTimeMillis(); System.out.println(current ); //После задержки в 1 с проверяем, был ли mPerson.getAge() выполнен дважды verify(mPerson, after(1000).times(2)).getAge(); System.out.println(System.currentTimeMillis() - current);
mPerson.getAge(); mPerson.getAge(); //проверятьметодсуществовать вызывался 2 раза до таймаута в 100мс verify(mPerson, timeout(100).times(2)).getAge();
@Test public void testVerifyZeroInteractions() { Person person = mock(Person.class); person.eat("a"); //Поскольку объект person взаимодействует, проверка здесь не удалась. Закомментируйте приведенный выше вызов, и проверка завершится успешно. verifyZeroInteractions(person); //Вы можете убедиться, что несколько объектов не взаимодействуют //verifyZeroInteractions(person,person2 ); }
@Test public void testVerifyZeroInteractions() { Person person = mock(Person.class); person.eat("a"); verify(person).eat("a"); //Обратите внимание, что это не достигнет цели проверки и не может быть смешано сverify(). verifyZeroInteractions(person,person2 ); }
Mockito проверяет значения параметров в естественном стиле Java: с помощью функцииquals(). Иногда, когда необходима дополнительная гибкость, вы можете использовать средства сопоставления аргументов:
// Используйте встроенный Сопоставитель AnyInt(). параметров when(mockedList.get(anyInt())).thenReturn("element"); // Использовать собственный Сопоставитель параметров( Верните свою собственную реализацию сопоставителя в существующей функции isValid(). ) when(mockedList.contains(argThat(isValid()))).thenReturn("element"); // выходelement System.out.println(mockedList.get(999)); // Вы также можете проверить Сопоставитель параметров verify(mockedList).get(anyInt());
Часто используемые средства сопоставления параметров:
методимя | значение |
---|---|
anyObject() | соответствовать любому объекту |
any(Class type) | То же, что и любой Объект(). |
any() | То же, что и любой Объект(). |
anyBoolean() | Соответствует любому логическому и непустому логическому значению. |
anyByte() | Соответствует любому байту и непустому байту |
anyCollection() | Соответствует любой непустой коллекции. |
anyDouble() | Соответствует любому двойному и непустому двойному значению. |
anyFloat() | Соответствует любому веществу с плавающей запятой и непустому значению с плавающей запятой. |
anyInt() | Соответствует любому целому непустому целому числу. |
anyList() | Сопоставить любой непустой список |
anyLong() | Соответствует любому длинному и непустому длинному значению. |
anyMap() | Сопоставьте любую непустую карту |
anyString() | Соответствует любой непустой строке |
contains(String substring) | Параметр содержит данную строку подстроки |
argThat(ArgumentMatcher matcher) | Создание шаблонов сопоставления пользовательских параметров |
eq(T value) | Параметр соответствия равен определенному значению |
Некоторый пример кода:
@Test public void testPersonAny(){ When(mPerson.eat(any(String.class))).thenReturn("рис"); //или: когда(mPerson.eat(anyString())).thenReturn("рис"); //выходрис System.out.println(mPerson.eat("Лапша")); } @Test public void testPersonContains(){ когда(mPerson.eat(contains("мясо"))).thenReturn("мясо"); //выход Лапша System.out.println(mPerson.eat("лицо")); } @Test public void testPersonArgThat(){ //Когда длина пользовательского входного символа является четным числом,выход Лапша。 when(mPerson.eat(argThat(new ArgumentMatcher<String>() { @Override public boolean matches(String argument) { return argument.length() % 2 == 0; } }))).thenReturn("Лапша"); //выход Лапша System.out.println(mPerson.eat("1234")); }
нуждаться Уведомлениеизда,Если вы планируете использовать Сопоставитель параметры, то все параметры должны быть предоставлены сопоставителем. Например:
verify(mock).someMethod(anyInt(), anyString(), eq("third argument")); // Приведенный выше код верен, поскольку eq() также является Сопоставителем. параметров verify(mock).someMethod(anyInt(), anyString(), "third argument"); // Приведенный выше код неверен, Поскольку все параметры должны быть предоставлены сопоставителем, а параметр «третий argument"не по Сопоставитель параметры предоставляет, поэтому выдается исключение
Функции сопоставления, такие как Как и любой объект(), eq(), не возвращают совпадения. Они внутренне записывают совпадения в стек.,и возвращает ложное значение,Обычно ноль.
Убедитесь, что последовательность выполнения в основномиспользоватьInOrder
функция
Например, проверьте последовательность выполнения функции фиктивного объекта:
@Test public void testInorder() { List<String> singleMock = mock(List.class); singleMock.add(«Сяо Мин»); singleMock.add(«Красный»); // Создайте объект inOrder для макетного объекта. InOrder inOrder = inOrder(singleMock); // Убедитесь, что функция добавления сначала выполняет add("Xiao Ming"), а затем add("Xiao Hong"), в противном случае произойдет сбой. inOrder.verify(singleMock).add(«Сяо Мин»); inOrder.verify(singleMock).add(«Красный»); }
Проверьте порядок выполнения функций нескольких макетных объектов:
@Test public void testInorderMulti() { List<String> firstMock = mock(List.class); List<String> secondMock = mock(List.class); firstMock.add(«Сяо Мин»); secondMock.add(«Красный»); // Создайте объекты inOrder для этих двух Mock-объектов. InOrder inOrder = inOrder(firstMock, secondMock); // Проверьте порядок их выполнения inOrder.verify(firstMock).add(«Сяо Мин»); inOrder.verify(secondMock).add(«Красный»); }
Порядок выполнения проверок очень гибкий. Вы можете выбрать один макетный объект или смешать несколько макетных объектов или создать объект InOrder только из тех макетных объектов, которые необходимо проверить по порядку.
следить за реальностьюобъектиспользоватьspy()
функциягенерировать,или Это также может быть как@Mockтаким образомиспользовать@Spy
аннотация Приходитьгенерировать一个мониторобъект,Когда вы создаете шпионский объект для реального объекта,существуют. Когда вы используете этот шпионский объект, реальный объект также будет называться,Если только его функция не заглушена. Используйте шпионские объекты как можно меньше,Вы также должны быть осторожны с формой при ее использовании.
@Test public void testSpy() { List<String> list = new ArrayList<>(); List<String> spy = spy(list); // Вы можете заглушить определенные функции when(spy.size()).thenReturn(100); // Вызов функций на реальных объектах spy.add("one"); spy.add("two"); // выход Первый элемент «единица» System.out.println(spy.get(0)); // Поскольку функция size() является заглушкой, здесь возвращается 100. System.out.println(spy.size()); // Проверить взаимодействие verify(spy).add("one"); verify(spy).add("two"); }
использовать@Spy
Генерировать объекты мониторинга:
@Spy
Person mSpyPerson;
@Test
public void testSpyPerson() {
//ВыведемPerson Реальная реализация getName() в добром, а не нулевом формате.
System.out.println(mSpyPerson.getName());
}
Важно понимать мониторинг реальных объектов! иногда,существоватьмониторобъектначальствоиспользоватьwhen(Object)
Приходить进行битькучада不Может能илинереальноиз。поэтому,когдаиспользоватьмониторобъект Пожалуйста, подумайте, когдаdoReturn|Answer|Throw()
функцияклан Приходить进行битькуча。Например:
List list = new LinkedList(); List spy = spy(list); // невозможно достичь : Поскольку при вызове spy.get(0) будет вызвана функция get(0) реального объекта, // В этот момент возникнет исключение IndexOutOfBoundsException, поскольку реальный объект List пуст. when(spy.get(0)).thenReturn("foo"); // Вам нужно использовать doReturn() для заглушки doReturn("foo").when(spy).get(0);
Захват параметров предназначен главным образом для подготовки к следующему этапу утверждения, пример кода:
@Test public void argumentCaptorTest() { List<Object> mock = mock(List.class); mock.add("John"); //Создаем тип параметра для захвата, вот String ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); //Вызов метода аргумента.capture() в параметре существующегоverifyметода для захвата входных параметров verify(mock).add(argument.capture()); //проверить захват параметра "Джон" assertEquals("John", argument.getValue()); }
@Test public void argumentCaptorTest2() { List<Object> mock = mock(List.class); mock.add("Brian"); mock.add("Jim"); ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); verify(mock, times(2)).add(argument.capture()); //Если имеется несколько вызовов параметров, аргумент.getValue() захватывает параметры последнего вызова assertEquals("Jim", argument.getValue()); //Если вы хотите получить все значения параметров, вы можете вызвать аргумент.getAllValues() assertArrayEquals(new Object[]{"Brian","Jim"}, argument.getAllValues().toArray()); }
Иногда объект, который мы хотим протестировать внутренне, должен зависеть от другого объекта, например:
public class User { private Address address; public void setAddress(Address address) { this.address = address; } public String getAddress() { return address.getDetail(); } }
public class Address { public String getDetail() { return "detail Address"; } }
Класс User внутренне зависит от класса Address. Когда мы тестируем, нам нужно смоделировать эти два объекта, а затем передать объект Address в User. Это будет довольно сложно, если Mockito будет слишком много зависимых объектов. Предоставилк Нет необходимости вводить вручнуюобъектизметод,первыйиспользовать@InjectMocks
аннотациянуждатьсявпрыснутыйизобъект,Например, Пользователь,Затемнуждаться Внедренная зависимостьизобъектиспользовать@Mock
или@Spy
аннотация,Затем Mockito автоматически завершит процесс инъекции.,Например:
@InjectMocks User mTestUser; @Mock Address mAddress; @Test public void argumentInjectMock() { When(mAddress.getDetail()).thenReturn("Ханчжоу, Чжэцзян"); System.out.println(mTestUser.getAddress()); }
Таким образом, вам не придется беспокоиться о пользователе Установитьадрес ,Просто добавьте аннотации к тому доброму, от которого должен зависеть Пользователь.,Затем сосредоточьтесь непосредственно на написании тестметода.
Или вы можете использовать @Spy для мониторинга внедрения реальных объектов:
@InjectMocks User mTestUser; @Spy Address mAddress; @Test public void argumentInjectMock() { // When(mAddress.getDetail()).thenReturn("Ханчжоу, Чжэцзян"); System.out.println(mTestUser.getAddress()); }
другой:
Еще одна более короткая версия непрерывных звонков:
// Первый вызов возвращает «один», второй вызов возвращает «два», а третий вызов возвращает «три». when(mock.someMethod("some arg")).thenReturn("one", "two", "three");
ссылка:Mockito Китайская документация
Фреймворк Mockito в основном отвечает потребностям, но имеет некоторые ограничения.,Например, static, Final, Private и т. д. нельзя высмеивать.,PowerMockito может решить эти проблемы,PowerMockito — это более мощный фреймворк, расширяющий другие фреймворки, такие как EasyMock. PowerMock использует собственный добрый загрузчик и манипуляции с байт-кодом для имитации статического метода.,Конструктор,finalдобрыйиметод,частныйметод,Удалите статические инициализаторы и т. д.
Добавьте зависимости:
testImplementation 'org.powermock:powermock-module-junit4:2.0.2' testImplementation 'org.powermock:powermock-module-junit4-rule:2.0.2' testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' testImplementation 'org.powermock:powermock-classloading-xstream:2.0.2'
Целевой класс:
public class CommonExample { public boolean callArgumentInstance(File file) { return file.exists(); } }
Тестовый класс:
public class CommonExamplePowerMockTest { @Test public void testCallArgumentInstance() { File file = PowerMockito.mock(File.class); CommonExample commonExample = new CommonExample(); PowerMockito.when(file.exists()).thenReturn(true); Assert.assertTrue(commonExample.callArgumentInstance(file)); } }
Обычный метод Mock заключается в передаче параметров Mock извне.,По сути, использование только Mockito одно и то же.,Это также можно сделать, используя чистый API Mockito.
public class CommonExample { public boolean callArgumentInstance(String path) { File file = new File(path); return file.exists(); } }
@RunWith(PowerMockRunner.class) @PrepareForTest(CommonExample.class) public class CommonExamplePowerMockTest { @Test public void callCallArgumentInstance2() throws Exception { File file = PowerMockito.mock(File.class); CommonExample commonExample = new CommonExample(); PowerMockito.whenNew(File.class).withArguments("aaa").thenReturn(file); PowerMockito.when(file.exists()).thenReturn(true); Assert.assertTrue(commonExample.callArgumentInstance("aaa")); } }
Единственное отличие от предыдущего состоит в том, что,Здесь объект File создается внутри метода теста.,В это времянуждатьсяпроходитьPowerMockito.whenNew(File.class).withArguments("aaa").thenReturn(file)
метод Создание моделированияFileиздействовать,когдаFileдобрыйкaaaиз Создание параметровизпора уже возвращатьсяmockвне Приходитьизfileобъект。同时В это времянуждатьсясуществоватьтестдобрыйначальстводобавить ваннотация@RunWith(PowerMockRunner.class)
и@PrepareForTest(CommonExample.class)
,Обратите внимание, что существованиедобрый добавлен выше,нетсуществоватьметодначальство,Вначале при добавлении существующего метода выдавалось сообщение, что тестметод не найден.,@PrepareForTest()
括号вобозначениеизда要тестиз Цельдобрый。
public class CommonExample { public boolean callFinalMethod(DependencyClass dependency) { return dependency.isValidate(); } } public class DependencyClass { public final boolean isValidate() { // do something return false; } }
@RunWith(PowerMockRunner.class) @PrepareForTest({CommonExample.class, DependencyClass.class}) public class CommonExamplePowerMockTest { @Test public void callFinalMethod() { DependencyClass dependency = PowerMockito.mock(DependencyClass.class); CommonExample commonExample = new CommonExample(); PowerMockito.when(dependency.isValidate()).thenReturn(true); Assert.assertTrue(commonExample.callFinalMethod(dependency)); } }
Точно так же и здесь насмешка должна опираться на объекты доброго характера.,а затем перешел к методу вызова,здесьтакой женуждатьсядобавить в@RunWith
и@PrepareForTest
,@PrepareForTest
Можеткобозначение多个Цельдобрый,Но вот если вам просто нужен тестфинал,Просто добавьте DependencyClass.class.
public final class Utils { public static String getUUId() { return UUID.randomUUID().toString(); } } public class CommonExample { public String printUUID() { return Utils.getUUId(); } }
@RunWith(PowerMockRunner.class) @PrepareForTest(Utils.class) public class StaticUnitTest { @Before public void setUp() throws Exception { PowerMockito.mockStatic(Utils.class); } @Test public void getUUId() { PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID"); CommonExample commonExample = new CommonExample(); assertThat(commonExample.printUUID(), is("FAKE UUID")); } }
такой женуждатьсяобозначение@RunWith
и@PrepareForTest
,@PrepareForTest
середина Укажите статическийметод Местосуществоватьиздобрый,тестстатическийметод ДонуждатьсявызовPowerMockito.mockStatic()
метод Приходитьmockстатическийдобрый,Затем Сразупроходитьwhen().thenReturn()
метод Укажите статическийметодиз模拟返回值即Может。
@Test public void testVerify() { PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID"); CommonExample commonExample = new CommonExample(); System.out.println(commonExample.printUUID()); PowerMockito.verifyStatic(Utils.class); Utils.getUUId(); }
статическийметодпроходитьPowerMockito.verifyStatic(Class c)
Проверять,Однако разница между этим и Mocktio заключается в том, что вам нужно вызывать статический метод после существования.,в противном случаенет。здесьPowerMockito.verifyStatic(Utils.class)
Фактически это эквивалентноPowerMockito.verifyStatic(Utils.class, times(1))
,Если вы хотите подтвердить более одного раза,Так:
@Test public void testVerify() { PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID"); CommonExample commonExample = new CommonExample(); System.out.println(commonExample.printUUID()); System.out.println(commonExample.printUUID()); PowerMockito.verifyStatic(Utils.class, Mockito.times(2)); Utils.getUUId(); }
На данный момент первый параметр PowerMockito.verifyStatic() указывает класс статического метода.,Второй параметр получает параметр VerificationModeтип.,Таким образом, передача любой функции в Mockito, которая проверяет время метода, будет работать.,Mockitoсерединаизпроверятьфункциявернетсяизда一个VerificationModeтип。такой жесуществоватьPowerMockito.verifyStatic
метод后лапша要вызов一次要проверятьизстатическийметод,Здесь всегда странно. . .
Если в процессе существованиятеста вы столкнулись с возвращаемым значением моделирования статического метода, которое не нужно имитировать,,Вместо этого требуется истинное возвращаемое значение.,Что делать,По сути, это то же самое, что и Mockito.,PowerMockitoтакой жепоставлятьthenCallRealMethod
илиdoCallRealMethod
метод:
@Test public void testRealCall() throws Exception { PowerMockito.when(Utils.getUUId()).thenReturn("FAKE UUID"); //... PowerMockito.when(Utils.getUUId()).thenCallRealMethod(); //Эквивалентно следующему //PowerMockito.doCallRealMethod().when(Utils.class, "getUUId"); System.out.println(Utils.getUUId()); }
Или вы можете напрямую использовать шпион для наблюдения за реальными объектами:
@Test public void testRealCall() { PowerMockito.spy(Utils.class); System.out.println(Utils.getUUId()); }
public class CommonExample { public boolean callPrivateMethod() { return isExist(); } private boolean isExist() { return false; } }
@RunWith(PowerMockRunner.class) @PrepareForTest(CommonExample.class) public class PrivateUnitTest { @Test public void testCallPrivateMethod() throws Exception { CommonExample commonExample = PowerMockito.mock(CommonExample.class); PowerMockito.when(commonExample.callPrivateMethod()).thenCallRealMethod(); PowerMockito.when(commonExample, "isExist").thenReturn(true); Assert.assertTrue(commonExample.callPrivateMethod()); } }
Использование существования мало чем отличается от чистого Mockito, за исключением того, что частный метод Mock реализуется через следующий API:
PowerMockito.when(Object instance, String methodName, Object... arguments)
существуют при работе в PowerMockito по сравнению с Mockito,Самое большое изменение заключается в том, что появилось больше перегрузок методаName, которые передают Stringтипметод.,Таким образом, существование можно использовать практически во всем.
public class CommonExample { private static final int STATE_NOT_READY = 0; private static final int STATE_READY = 1; private int mState = STATE_NOT_READY; public boolean doSomethingIfStateReady() { if (mState == STATE_READY) { // DO some thing return true; } else { return false; } } }
@Test public void testDoSomethingIfStateReady() throws Exception { CommonExample sample = new CommonExample(); Whitebox.setInternalState(sample, "mState", 1); assertThat(sample.doSomethingIfStateReady(), is(true)); }
проходитьWhitebox.setInternalState
Приходить Изменятьчастныйпеременные-члены,В данном случае нетнуждатьсяобозначение@RunWith
и@PrepareForTest
。
public class CommonExample { public static void doSomething(String a) { System.out.println("doSomething"+a); } }
@RunWith(PowerMockRunner.class) @PrepareForTest({CommonExample.class}) public class StaticUnitTest { @Test public void testStaticVoid() throws Exception { PowerMockito.mockStatic(CommonExample.class); PowerMockito.doNothing().when(CommonExample.class, "doSomething", Mockito.any()); CommonExample.doSomething("aaa"); } }
По умолчаниюпроходитьPowerMockito.mockStatic
изстатическийдобрыйизvoidизметодда什么也不做из,Однако doNothing можно выполнить явно. Закомментирование строки doNothing в приведенном выше коде ничего не даст. Что, если вы хотите что-то сделать вместо doNothing?,То же, что Мокито,использоватьdoAnswer
:
@Test public void testStaticVoid() throws Exception { PowerMockito.mockStatic(CommonExample.class); PowerMockito.doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { System.out.println(invocation.getArguments()[0]); return null; } }).when(CommonExample.class, "doSomething", Mockito.any()); CommonExample.doSomething("aaa"); }
public class CommonExample { public int callSystemStaticMethod(int a, int b) { return Math.max(a, a+b); } }
@RunWith(PowerMockRunner.class) @PrepareForTest(CommonExample.class) public class StaticUnitTest { @Test public void callSystemStaticMethod() { CommonExample commonExample = new CommonExample(); PowerMockito.mockStatic(Math.class); PowerMockito.when(Math.max(anyInt(), anyInt())).thenReturn(100); Assert.assertEquals(100, commonExample.callSystemStaticMethod(10, -5)); } }
@PrepareForTest
Добавить систему звонков вдобрый Местосуществоватьиздобрый,Здесь следует отметить, что если вы используете PowerMockito для издевательства над системой, статический финалдобрый,Тогда вы больше не сможете добавлять простые библиотеки зависимостей Mockito к своим зависимостям gradle.,В противном случае издевательство здесь не удастся.,подскажетMockito can not mock/spy final class
, Поскольку сам PowerMockito уже имеет поддержку библиотеки зависимостей для Mockito, вы можете полагаться только на PowerMockito. За исключением ситуации, когда система является статически окончательной, в других случаях на PowerMockito и Mockito можно положиться одновременно (я тестирую без проблем). Кроме того, новая версия простого Mockito также поддерживает final добрый final методиз Макет, но добавлять файлы конфигурации неудобно.
Поскольку часть Робоэлектрика относительно длинная,,Месток单独放了一篇文章середина:Изучение и использование фреймворка модульного тестирования Android Robolectric
Espresso — это тестовая среда для тестирования инструментов Android.,Это библиотека, официально продвигаемая Google. Поскольку содержание части «Эспрессо» также относительно длинное.,Месток单独放了一篇文章середина:Использование фреймворка Espressotest
Издатель: Лидер стека программистов полного стека, укажите источник для перепечатки: https://javaforall.cn/155001.html Исходная ссылка: https://javaforall.cn