Spring Данные: тестирование модуля уровня сервиса
В моем проекте у меня проблемы с тестированием модулей. Одна из проблем заключается в том, что просто делать интеграционный тест гораздо быстрее, чтобы писать, а также проверять, что компоненты работают вместе. Единичное тестирование новых "алгоритмов" или так кажется намного проще. Единица тестирования классов обслуживания это просто кажется неправильным и бесполезным.
Я использую mockito для издевательства репозитория данных spring (и, следовательно, доступа к БД). Дело в том, что если я скажу, что издеваемое хранилище вернет объект A на вызов метода getById, он, очевидно, вернет его, и служба вернет его тоже. Да, служба делает некоторые дополнительные вещи, но очень незначительные вещи, такие как нагрузка ленивых коллекций (из спящего режима). Очевидно, что у меня нет ленивых коллекций (прокси) в unit test.
Пример:
@Test
public void testGetById() {
System.out.println("getById");
TestCompound expResult = new TestCompound(id, "Test Compound", "9999-99-9", null, null, null);
TestCompoundRepository mockedRepository = mock(TestCompoundRepository.class);
when(mockedRepository.findOne(id)).thenReturn(expResult);
ReflectionTestUtils.setField(testCompoundService, "testCompoundRepository",
mockedRepository, TestCompoundRepository.class);
TestCompound result = testCompoundService.getById(id);
assertEquals(expResult, result);
}
Ура, остальное удаётся. Какой сюрприз! Не на самом деле нет.
Может кто-нибудь объяснить мне, что я делаю неправильно? Или что точка такого теста? Я имею в виду, я говорю, чтобы вернуть expResult, а затем он возвращается. Вау. Какой сюрприз! Похоже, я тестирую, работает ли mockito, а не моя Служба.
EDIT:
Единственное преимущество, которое я вижу, если некоторые из них были глупые ошибки, происходит, как оставляя ненужную строку там, которая устанавливает возвращаемое значение в null или что-то подобное глупое. Такие случаи были бы пойманы unit test. Тем не менее соотношение "вознаграждение-усилие" кажется плохим?
Ответы
Ответ 1
Одна из причин, по которой мне нравится тестировать мои репозитории данных Spring, - это проверить, что я правильно определил свои сопоставления JPA. Я не использую фальшивую структуру для этих тестов, я использую структуру Spring Test, которая фактически загружает контейнер, позволяя мне авторизовать фактический репозиторий в тесте Junit, чтобы я мог выполнять тесты против него.
Я согласен с вашими мыслями, что издевательство над репозиторием довольно бесполезно. Поскольку вы используете Spring, я бы предложил использовать платформу Spring Test для выполнения реальных тестов с вашими репозиториями, которые могут быть выполнены против встроенной базы данных, такой как H2, на основе более unit test или вашей реальной реализации базы данных, такой как Oracle или MySql, чтобы провести больше интеграционного теста. (Выполните их против копии базы данных разработки). Эти тесты выявят ошибки в ваших сопоставлениях JPA и других элементах, таких как неправильная настройка каскадов в базе данных.
Вот пример одного из моих тестов на GitHub. Обратите внимание на то, как инфраструктура фактически обновляет репозиторий в тесте. В репозитории также приведен пример настройки тестовой среды Spring, которую я также продемонстрировал в этом сообщении .
В заключение я не считаю, что вы получите какие-либо преимущества тестирования репозитория, который я обсуждал, используя макет репозитория.
Еще одно примечание, которое я хотел добавить, заключается в том, что макеты на самом деле не предназначены для использования в текущем тестируемом классе. Их использование предназначено для предоставления требуемых зависимостей тестируемому классу.
Ответ 2
Вопрос может быть немного старым, но я отвечу на случай, если кто-то споткнутся.
- Я использую Mockito и JUnit.
- AccountRepository - это простой репозиторий данных spring, расширяющий JPARepository.
- Учетная запись - это простой объект JPA.
Чтобы протестировать ваши сервисы и издеваться над репозиториями spring Data, вам нужно что-то вроде ниже.
package foo.bar.service.impl;
import foo.bar.data.entity.Account;
import foo.bar.data.repository.AccountRepository;
import foo.bar.service.AccountService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest {
@Mock
private static AccountRepository accountRepository;
@InjectMocks
private static AccountService accountService = new AccountServiceImpl();
private Account account;
@Test
public void testFindAccount() {
Integer accountId = new Integer(1);
account = new Account();
account.setId(accountId);
account.setName("Account name");
account.setCode("Accont code");
account.setDescription("Account description");
Mockito.when(accountRepository.findOne(accountId)).thenReturn(account);
Account retrivedAccount = accountService.findAccount(accountId);
Assert.assertEquals(account, retrivedAccount);
}
}
Ответ 3
Ты точно прав. Ясно, что unit test. И он никогда не потерпит неудачу (так что это бесполезно). Я думаю, что вам нужно пройти тест интеграции, чтобы протестировать репозиторий JPA реального с помощью реальной базы данных (H2
в памяти, например) (как я всегда это делаю).
И лучше проверить свои сервисы (их интерфейсы). Если через некоторое время вы измените свое хранилище (например, на Mongo), вы сможете использовать свои тестовые тесты для обеспечения того, чтобы все работало по-прежнему.
Через некоторое время вы будете удивлены, сколько проблем с DB\JPA (ограничения, оптимистичные блокировки, ленивая загрузка, дублированный идентификатор, некоторые проблемы с гибернацией и т.д.).
Кроме того, попробуйте разработать через тесты - а не просто написать тест после реализации. Вместо этого перед созданием нового метода в сервисе - создайте для него тест, реализуйте метод сервиса и только после того, как просто перепроверьте его в реальном приложении. По крайней мере, гораздо быстрее начать тест, чем сервер.
Итак, не создавайте тесты, чтобы их было много. Найдите, как они могут вам помочь.
Использование mocks для репозиториев - не очень хорошая идея. Проверьте, как ваши службы работают вместе с Hibernate\JPA\Database. Большая часть проблем находится beetwen layers.
Ответ 4
Вы можете использовать эту библиотеку: https://github.com/agileapes/spring-data-mock
Это высмеивает ваш репозиторий для вас, позволяя вам реализовать пользовательские функции для любого метода, а также для собственных методов запросов.