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, много расскажите о вашем коде, если они не сработают, и их гораздо легче понять, чем те, которые создают множество штучных объектов.

Я предпочел бы ошибиться в стороне от тривиальности тестов, чем со стороны слишком сложных тестов: слишком сложные тесты замедлят вас, а не обеспечат осмысленное понимание. Обычно они терпят неудачу, потому что предположение о среде выполнения является ложным и должно быть исправлено.