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