JUnit и Mocks в Лиферэй
Мне нужно сделать тесты JUnit, используя Mockito или PowerMock или что-то еще, но я не знаю, с чего начать. Я создал тестовую папку, установил mockito, но что мне делать дальше? Я не мог найти никаких примеров, поэтому я застрял в этом. Можете ли вы показать мне, как написать этот тест JUnit или хотя бы дать некоторую идею.
public void deleteAuthor(ActionRequest actionRequest, ActionResponse actionResponse)
throws SystemException, PortalException {
long authorId = ParamUtil.getLong(actionRequest, "authorId");
AuthorLocalServiceUtil.deleteAuthor(authorId);
SessionMessages.add(actionRequest, "deleted-author");
log.info(DELETE_SUCCESS);
}
Или это:
public void addAuthor(ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException, SystemException {
String authorName=ParamUtil.getString(actionRequest,"authorName");
Author author=AuthorLocalServiceUtil.createAuthor(CounterLocalServiceUtil.increment());
author.setAuthorName(authorName);
author=AuthorLocalServiceUtil.addAuthor(author);
}
P.S. Я очень новичок и сделал всего 1 тест JUnit в своей жизни, поэтому Im действительно заинтересовался хорошим советом. Спасибо заранее!
UPD:
Я пытаюсь сделать что-л. следующим образом:
private BookAndAuthor portlet;
@Before
public void setUp() {
portlet = new BookAndAuthor();
}
@Test
public void testDeleteBookOk() throws Exception {
PowerMockito.mockStatic(BookLocalServiceUtil.class);
long id = 1;
Book book = BookLocalServiceUtil.createBook(id);
ActionRequest actionRequest = mock(ActionRequest.class);
ActionResponse actionResponse = mock(ActionResponse.class);
when(BookLocalServiceUtil.deleteBook(book)).thenReturn(null);
Book result = BookLocalServiceUtil.deleteBook(book);
assertEquals(result, null);
}
... но без успеха.
Ответы
Ответ 1
Мы запускаем тест JUnit
, используя следующую настройку:
i. Создайте папку test
рядом с docroot
в вашем портлете.
ii. Добавьте unit
папку для проверки и создания package
в ней.
iii. Создайте portal-ext.properties
файл в папке test
со следующей конфигурацией:
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost:3309/db_name?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=your_username
jdbc.default.password=your_password
jdbc.default.automaticTestTable=C3P0TestTable
jdbc.default.idleConnectionTestPeriod=36000
jdbc.default.maxIdleTime=1200
iv. Создайте класс класса (скажем AbcSuite.java
) следующим образом:
package x.x.x;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import com.liferay.portal.util.InitUtil;
@RunWith(Suite.class)
@Suite.SuiteClasses({
// Where AxTest.class would be your test class name
A1Test.class, A2Test.class, AxTest.class
})
public class AbcSuite {
@BeforeClass
public static void setUp() throws Exception {
// Loading properties and establishing connection with database
InitUtil.initWithSpring();
System.out.println("X Portlet Test Suite Execution : Started.");
}
@AfterClass
public static void tearDown() {
System.out.println("X Portlet Test Suite Execution : Completed.");
}
}
v. Создайте тестовый класс (скажем A1Test.java
) следующим образом:
package x.x.x;
import java.util.ArrayList;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class A1Test {
@BeforeClass
public static void setUp() throws Exception {
System.out.println("Test Running : A1Test");
}
@Test
public void testAddAuthor() {
Author author = AuthorLocalServiceUtil.createAuthor(
CounterLocalServiceUtil.increment());
author.setAuthorName("Testcase Author");
author = AuthorLocalServiceUtil.addAuthor(author);
Assert.assertNotNull(author);
Assert.assertTrue(author.getAuthorId() > 0);
}
}
Что это! Вы можете выполнить все тестовые примеры вместе, используя следующую команду:
ant test -Dtest.class=AbcSuite*
или отдельно как:
ant test -Dtest.class=A1Test*
Ответ 2
Это будет непопулярный ответ, но...
Я обнаружил, что тесты JUnit с множеством насмешливых объектов не особенно полезны. Баланс возникает при просмотре размера метода setUp()
вашего теста: чем дольше это, тем меньшее значение имеет тест. В мире портлетов вам нужно будет использовать много макетов, и вы будете более заняты зеркалированием среды выполнения (и исправлением сделанных вами предположений), чем устранение проблем, которые вы обнаружили только при создании этого вид тестов.
Это, как говорится, здесь мой рецепт
-
Создайте свои портлеты с одной целью: портлеты - это технология пользовательского интерфейса. Пользовательский интерфейс по своей сути трудно проверить автоматически. Вы застряли между стандартом JSR-286 и бизнес-слоем - два слоя, которые, вероятно, не особенно хорошо подходят для их подключения в тестах.
-
Сохраняйте свой код уровня пользовательского интерфейса настолько смехотворно простым, что вы можете просто немного пересмотреть код. Вы узнаете больше об этом, чем о сложных процедурах setUp() ваших тестов JUnit.
-
Фактор из значимого кода пользовательского интерфейса. Извлеките его в свой собственный класс или метод. Проверьте, что - обратите внимание, что вам, вероятно, даже не нужен полный объект PortletRequest для него, используйте только фактические данные, которые ему нужны.
-
Создайте тесты интеграции поверх всего этого. Они будут использовать полный стек, ваше приложение развернуто в тестовой среде. Они предоставят smoke test, чтобы увидеть, действительно ли ваш код работает. Но убедитесь, что проверка правильной проводки не мешает вам: Код сложности object.setStreet(request.getParameter("street"));
не должен быть протестирован, скорее проверен код - и он должен быть либо явно правильным, либо явно неправильным.
-
Используйте правильные стандарты кодирования, чтобы упростить просмотр. Например. назовите свое поле ввода "улица", если данные хранятся, а не "input42"
Учитывая это: всякий раз, когда вы пишете портлет с кодом, который, по вашему мнению, должен быть протестирован: Извлеките его. Устраните необходимость фальсификации объектов портлета или вашего бизнес-уровня. Проверьте извлеченный код. Второй { code block }
в рамках метода портлета может быть достаточно запаха кода, чтобы оправдать извлечение в отдельный класс/метод, который обычно можно протестировать тривиально - и эти тесты будут полностью независимы от Liferay, много расскажите о вашем коде, если они не сработают, и их гораздо легче понять, чем те, которые создают множество штучных объектов.
Я предпочел бы ошибиться в стороне от тривиальности тестов, чем со стороны слишком сложных тестов: слишком сложные тесты замедлят вас, а не обеспечат осмысленное понимание. Обычно они терпят неудачу, потому что предположение о среде выполнения является ложным и должно быть исправлено.