Tag Archives: Maven

FitNesse with Maven

Доброго времени суток.

Вот и завершилась, как уже кажется, безконечная череда праздников и все возвращается на “круги своя”. И как было обещано в предыдущем посте, в этот раз я поделюсь небольшими навыками с интеграции FitNesse в Maven build  lifecycle.

На первый взгляд, мне так тоже казалось, что тут нет ничего сложного и все уже есть. Проштудировав документацию + internet на предмет наличия интеграции FitNesse с Maven, я кое что нашел. Тут доступен fitnesse-maven-plugin plugin для Maven, который должен обеспечить вас возможностью выполнять ваши FitNesse тесты и создавать репорты. Но что бы выполнить тесты, FitNesse сервер должен быть запущен. Для этих целей я подходящего ничего не нашел, к тому же это все должно происходить во время выполнения билда.

Для запуска FitNesse сервера я написал plugin для Maven, исходники можно найти тут.  Далее привожу пример конфигурации плагина:

<plugin>
	<groupId>name.webdizz</groupId>
	<artifactId>maven-fitnesse-server</artifactId>
        <version>0.0.1-SNAPSHOT</version>
	<executions>
		<execution>
			<phase>pre-integration-test</phase>
			<id>start-fitnesse-server</id>
			<goals>
				<goal>start-server</goal>
			</goals>
			<configuration>
				<background>true</background>
				<port>9292</port>
				<baseDir>${basedir}/src/test</baseDir>
				<root>fitnesse</root>
				<omitUpdates>true</omitUpdates>
			</configuration>
		</execution>
	</executions>
	<dependencies>
		<dependency>
			<groupId>org.fitnesse</groupId>
			<artifactId>fitnesse</artifactId>
			<version>20091121</version>
		</dependency>
		<dependency>
			<!-- Тут идут ваши зависимости - т.е. фитнесс-тесты -->
		</dependency>
	</dependencies>
</plugin>

Запуск сервера настроен на pre-integration-test фазу, так как сами тесты выполняются в integration-test фазе.

Со стартом мы определились, теперь же нужно разобраться с запуском непосредственно тестов. Привожу свою конфигурацию плагина для выполнения тестов.

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>fitnesse-maven-plugin</artifactId>
        <version>1.0-custom</version>
	<configuration>
		<classPathProvider>maven</classPathProvider>
		<!-- FitNesse servers list -->
		<fitnesses>
			<fitnesse>
				<hostName>localhost</hostName>
				<port>9292</port>
				<!-- The should be a suite to run all tests -->
				<pageName>FitNesse.UserGuide.SlIm.ScriptTable</pageName>
				<type>test</type>
			</fitnesse>
		</fitnesses>
	</configuration>
	<executions>
		<execution>
			<id>integration-test-fitnesse</id>
			<phase>integration-test</phase>
			<goals>
				<goal>run</goal>
			</goals>
		</execution>
	</executions>
</plugin>

Но на этапе запуска возникла проблема с выполнением тестов. Как оказалось fitnesse-maven-plugin немного устарел – последнее обновление было аж “04/06/2008” и запуск тестов валился с ошибкой неверных коммандных атрибутов. Проблема была с параметром “-html” – версия FitNesse, которую я использовал, уже не поддерживала такой аттрибут. Пришлось править код – заменил этот “-html” на “-xml” – заработало :).

На этом мне еще не удалось выполнить тест, так как появилась новая проблема – результат выполнения тестов сохранялся в виде XML, плагин же ожидает его в HTML. В итоге пришлось еще немного допилить пару классов, как результат – все заработало. Модифицированные исходники можно взять отсюда.

Теперь, используя стандартную команду

mvn clean install

будет стартовать FitNesse сервер и выполняться тесты.

На этом все, спасибо за внимание и удачного тестирования…

FitNesse или еще один подход приемочного тестирования

Как я уже писал, хотел сказать выше, но в нашем контексте это не очень соотвествует реальности, поэтому говорю ниже – с недавних пор я на новом проекте и продолжаю получать впечатления определенного характера;)

Еще одним из таковых является Acceptance Tests. В качестве движка для этого на проекте используется FitNesse – как написано на официальном сайте – “The fully integrated standalone wiki, and acceptance testing framework.“. Рассказывать что такое приемочное тестирование и FitNesse я не буду (можно пройтись по ссылкам и получить достаточное количество знаний), а хочу описать способ применения этого фреймворка на нашем проекте.

Итак, мы используем возможность, предоставляющую фреймворком – создавать Fixture для приемочных тестов в виде таблиц. Но я бы не писал об этом, если это бы это было простое использование FitNesse. Наши тесты используют так называемую Narrative идеологию. То есть каждый тест состоит из набора предусловий, действий и проверок и выглядит очень читаемым для участников проекта, не принимающих участие в разработке и тестировании – то бишь менеджмент. Ниже приведу пример теста:

| Given that | Actor | Able to do something | – Предусловие, что пользователь может что-то делать. Например залогиниться в приложение.

| When | Actor | Attempts to click on view story button | – Действие, пользователь приложение нажимает или делает что-то с элементами интерфейса.

| Then | Displayed story is | id “some id” | – Проверка, что после действий пользователь интерфейс изменился и состояние соотвествует определенным значением. В данном случае это ID истории должен быть равен “some id”.

Получается очень даже читабельно и удобно.

В нашем случае тестированию подлегает интерфейс приложения, web-приложения. Технически это выглядит следующим образом. FitNesse выполняет код Narrative фикстур, а фикстуры в свою очередь используют WebDriver для работы с DOM моделью браузера.

Одним из дополнительных способов использования такого подхода я вижу – обучающие тесты. То есть фикстуры делают паузы и подсвечивают элементы, показывают подсказки над элементами интерфейса. Прадва тут нужна возможность паузы и прокрутки тестов с нужного шага.

На жтом все. В следующем топике хочу поделиться своим опытом использования FitNesse с Maven.

GWT-2.x and maven

Хочу поделиться скриптом, который мне помогает сохранить время при работе над GWT-2.x проектом. В виду того, что эта ветка находиться в постоянной разработке, но использование стабильной ветки не подходит, то необходимо периодически обновляться до актуальной версии. Мы используем Maven для сборки проекта и локальный репозиторий (Artifactory) и после каждого обновления нужно деплоить в репозиторий новые джарники. Что бы избавиться от рутины предлагаю воспользоваться следующим скриптом. Ни чего замысловатого – просто вызов mvn deploy-file …. Ниже собственно содержимое скрипта:

@echo off
 
echo ====================================================================================
echo Start deploying GWT artifacts
echo ====================================================================================
 
SET GWT_SDK_VERSION=2.0.0
SET GWT_SDK_PATH=D:\src\lib\gwt2\trunk\build\staging\gwt-windows-2.0.0
SET REPO=http://artifactory:8081/artifactory/libs-releases-local
SET LREPO=file:///D:\src\repository
 
echo ====================================================================================
echo Deploy gwt-servlet.jar
echo ====================================================================================
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%REPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-servlet.jar -DartifactId=gwt-servlet 
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%LREPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-servlet.jar -DartifactId=gwt-servlet 
 
echo ====================================================================================
echo Deploy gwt-user.jar
echo ====================================================================================
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%REPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-user.jar -DartifactId=gwt-user 
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%LREPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-user.jar -DartifactId=gwt-user 
 
echo ====================================================================================
echo Deploy gwt-dev-oophm.jar
echo ====================================================================================
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%REPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-dev-oophm.jar -DartifactId=gwt-dev-oophm 
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%LREPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-dev-oophm.jar -DartifactId=gwt-dev-oophm 
 
echo ====================================================================================
echo Deploy gwt-dev-windows.jar
echo ====================================================================================
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%REPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-dev-windows.jar -DartifactId=gwt-dev -Dclassifier=windows
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%LREPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=jar -Dfile=%GWT_SDK_PATH%/gwt-dev-windows.jar -DartifactId=gwt-dev -Dclassifier=windows
 
echo ====================================================================================
echo Deploy gwt-dev-windows-libs.zip
echo ====================================================================================
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%REPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=zip -Dfile=%GWT_SDK_PATH%/gwt-dev-windows.jar -DartifactId=gwt-dev -Dclassifier=windows-libs
call mvn deploy:deploy-file -DrepositoryId=artifactory -Durl=%LREPO% -DgeneratePom=true -DgroupId=com.google.gwt -Dversion=%GWT_SDK_VERSION% -Dpackaging=zip -Dfile=%GWT_SDK_PATH%/gwt-dev-windows.jar -DartifactId=gwt-dev -Dclassifier=windows-libs

Отладка GWT приложений на внешнем контейнере

Background

В предыдущем посте было упомянуто о необходимости запускать GWT приложение в Hosted Mode, используя при этом dmServer, тут же я бы хотел поделиться шагами, через которые мне пришлось пройти, чтобы реализовать эту возможность.

Итак как это было…

Прочитав FAQ тут, как говорится с “пол пинка” не завелось к сожалению( Но на этом мое намерение отлаживать мое приложение в dmServer не испарилось. Что я сделал – изменил настройки ланчера для запуска приложения в Hosted Mode: изменил параметр для открытия URL -startupUrl и добавил парметр, говорящий ланчеру не запускать встроенный сервлет контейнер (для GWT 1.7 – Jetty). Содержимое конфигурационного файла приведено ниже.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
	<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
		<listEntry value="/stock-watcher" />
	</listAttribute>
	<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
		<listEntry value="4" />
	</listAttribute>
	<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables"
		value="true" />
	<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
		<listEntry
			value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;stock-watcher&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;" />
		<listEntry
			value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/stock-watcher/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;" />
		<listEntry
			value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;stock-watcher&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;" />
	</listAttribute>
	<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER"
		value="org.maven.ide.eclipse.launchconfig.classpathProvider" />
	<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH"
		value="false" />
	<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE"
		value="com.google.gwt.dev.HostedMode" />
	<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS"
		value="-startupUrl http://localhost:8080/stock-watcher/StockWatcher.html&#13;&#10;name.webdizz.gwt.stock.watcher.StockWatcher&#13;&#10;-war src/main/webapp&#13;&#10;-noserver" />
	<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR"
		value="stock-watcher" />
	<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER"
		value="org.maven.ide.eclipse.launchconfig.sourcepathProvider" />
	<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS"
		value="-Xmx256M" />
</launchConfiguration>

На этом мои действия, исходя из смысла приведенной выше статьи, должны были увенчаться успехом, но это было не совсем так. Дальнейшие “танцы с бубном” показали, что так как я использую Maven для сборки проекта и, в частности, gwt-maven-plugin для компиляции GWT специфичных артифактов, проблема скрывалась за несогласованными действиями Google Eclipse plugin и Maven. Этот момент был устранен настройкой maven-war-plugin в файле pom.xml проекта stock-watcher. Я исключил копирование содержимого директории src/main/webapp/stockwatcher из src/main/webapp/ (директива warSourceExcludes).

46
47
48
49
50
51
52
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-war-plugin</artifactId>
	<configuration>
		<warSourceExcludes>**/stockwatcher/**</warSourceExcludes>
	</configuration>
</plugin>

`После этого собранный проект с помошью команды

mvn clean install

Результат сборки копируем в pickup директорию dmServer-а и запускаем ланчер в Eclipse. Ставим breakpoint и наслаждаемся…;) правда перед тем как окунуться в дебаг не знаю почему, но необходимо Hosted Browser рефрешить 5 раз и на 6-ой мы попадаем на точку останова)).

Debugging GWT application
Debugging GWT application