Я работаю над обновлениями для нескольких надстроек Roo, которые скоро собираюсь выпустить в репозиторий Roo. Вот некоторые проблемы и как я их преодолел.
Интерфейсный маркерный интерфейс команды
Это дополнение устанавливает Coffeescript с помощью плагина Maven. Вот источник дополнения:
package org.sillyweasel.addons.coffeescript;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.shell.CliAvailabilityIndicator;
import org.springframework.roo.shell.CliCommand;
import org.springframework.roo.shell.CliOption;
import org.springframework.roo.shell.CommandMarker;
@Component
@Service
public class CoffeescriptCommands implements CommandMarker {
/**
* Get a reference to the CoffeescriptOperations from the underlying OSGi
* container
*/
@Reference
CoffeescriptOperations operations;
@CliAvailabilityIndicator({"coffeescript setup"})
public boolean isSetupCommandAvailable() {
return operations.isSetupCommandAvailable();
}
@CliAvailabilityIndicator({"coffeescript remove", "coffeescript addjoinset",
"coffeescript removejoinset",
"coffeescript listjoinsets"})
public boolean isCoffeescriptInstalled() {
return operations.isPluginInstalled();
}
@CliCommand(value = "coffeescript setup",
help = "Install the CoffeeScript compiler")
public void setup(
@CliOption(key = "outputDirectory", mandatory = false,
unspecifiedDefaultValue = "${project.build.directory}") String outputDirectory,
@CliOption(key = "coffeeDir", mandatory = false,
unspecifiedDefaultValue = "src/main/webapp/scripts",
specifiedDefaultValue = "src/main/webapp/scripts") String coffeeDir,
@CliOption(key = "bare", mandatory = false,
unspecifiedDefaultValue = "false",
specifiedDefaultValue = "true") boolean bare) {
operations.setup(coffeeDir, outputDirectory, bare);
}
public void addJoinSet(
@CliOption(key = "joinSetId", mandatory = true, specifiedDefaultValue = "main")
String joinSetId,
@CliOption(key = "includes", mandatory = true,
help = "comma-separated list of search paths for javascript files to include")
String includes,
@CliOption(key = "excludes", mandatory = true,
help = "comma-separated list of search paths for javascript files to exclude")
String excludes) {
// TODO - set up the command
}
@CliCommand(value = "coffeescript remove", help = "Remove the coffeescript compiler")
public void remove() {
operations.remove();
}
}
Кое-что из этого я еще не написал (отсюда и TODO ), а остальное уточняется, и я расскажу об этом позже.
Задача № 1 — аддоны Roo не включают JUnit?
Прямо сейчас нет. ( ROO -3161 ) Тем не менее, вы можете просто добавить его yerself. Я использую Mockito для насмешек (подробнее об этом позже), а также бездельничаю с этими прекрасными матчами Hamcrest:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency>
Задача № 2 — Вам нужно расширить видимость объектов OSG i, введенных Roo, чтобы их высмеивать
Поскольку мы хотим выполнить модульное тестирование наших надстроек, не запуская контейнер OSG i, нам нужно будет что-то делать. Я использую Mockito , отличную библиотеку для шуток и насмешек . Но я не могу добраться до внедренных объектов, и тест, который я собираюсь показать здесь, должен сделать «издевательство» над службой ProjectOperations Roo. Это определяется так в коде класса реализации Operations:
private @Reference ProjectOperations projectOperations;
Проблема в том, что я не могу просто использовать метод Mockito для получения доступа и фальсификации. Итак, я расширился до дружественной области, которая позволяет получить доступ из одного пакета. Я полагаю, что лучшим способом было бы создать геттер, но тогда я представляю его в более широком диапазоне, чем просто конкретный пакет дополнения:
@Reference ProjectOperations projectOperations;
Задача № 3 — как проверить маркер команды
Итак, первое, что я хочу сделать, это убедиться, что мой Command Marker вызывает правильные методы реализации команд. Сначала расширим ссылку на нашу переменную CoffeescriptOperations:
@Reference CoffeescriptOperations operations;
Затем мы пишем метод, который использует Mockito для имитации вызовов к объекту операций. Это тестовый класс:
package org.sillyweasel.addons.coffeescript;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;
public class CoffeescriptCommandsTest {
private CoffeescriptCommands commands;
@Before
public void setUp() {
commands = new CoffeescriptCommands();
commands.operations = mock(CoffeescriptOperations.class);
}
@Test
public void testIsPluginInstalled() {
when(commands.operations.isPluginInstalled()).thenReturn(false);
assertThat(commands.isCoffeescriptInstalled(), is(false));
}
@Test
public void testIsCoffeescriptSetupAvailable() {
when(commands.operations.isSetupCommandAvailable()).thenReturn(true);
assertThat(commands.isSetupCommandAvailable(), is(true));
}
@Test
public void testIsCoffeescriptRemoveAvailable() {
when(commands.operations.isPluginInstalled()).thenReturn(true);
assertThat(commands.isCoffeescriptInstalled(), is(true));
verify(commands.operations, times(1)).isPluginInstalled();
}
@Test
public void testInstallCoffeeScript() {
commands.setup("foo", "bar", true);
verify(commands.operations).setup("foo", "bar", true);
}
@Test
public void testRemoveCoffeeScript() {
commands.remove();
}
@Test
@Ignore
public void testFileSets() {
Assert.fail();
}
}
Видишь, как я использую там какие-нибудь спички Hamcrest? Мне нравится синтаксис assertThat (…, is ()).
Итак, теперь мы знаем, что наш маркер команды фактически вызывает методы делегата, когда он вызывается. И мы на пути к тому, чтобы смоделировать все, что захотим, при условии, что мы немного расширим область видимости из 100% внутренней закрытой переменной-члена.
В нашем следующем посте я покажу вам, как проверить фактическую конфигурацию XML . Этот будет довольно большим, поэтому я разделю его на другой.