Так сложилось, что наша контора пишет на J2ME много и давно, но никогда не пользовалась unit-тестами. А я, прочитав несколько зажигательных статей на Хабре, проникся светлыми идеями unit-тестов и захотел хотя бы попробовать. Мои коллеги пожали плечами и заявили, что JUnit всё равно не заработает на J2ME, да и вообще, как тесты-то прогонять? На мобилке? В результате, у меня всё получилось, хотя и пришлось повозиться.
Выбор был невелик. Google сообщил мне, что существуют такие варианты:
Я, каюсь, выбрал, не глядя, вариант SE. Из соображений в духе «ну JUnit от SE наверняка должен без проблем работать с эмуляторами SE». Возможно, это был самый неудачный вариант… 8)
Скачанный архив содержал библиотеки, пример кода и пример тасков ant`а.
Процитирую один из тасков:
Видно, что вызывается некий класс с разными параметрами. Нигде, кстати, не документированными. Копипаст результатов не дал. Проблема была в bootclasspath. Вдумчивое чтение декомпилированного кода показало, что библиотека кушает параметры вида --<name>:<value>;<name>:<value>… При этом нереально записать в bootclasspath список либов, путь к каждой из которых начинается с C:. И, кстати, пробелы оно воспринимает как разделители наравне с точкой с запятой. Так что, никаких «Program Files». Решилось всё это распаковкой нужых либов в одну директорию и указанием пути к ней в bootclasspath.
После всех поправок вызов java выглядит так:
После описанных действий тестовый мидлет собирался и запустился. Но тесты падали с ошибками. Лечение же свелось к тому, что не надо создавать в тестах экземпляр своего мидлета. То есть, вот так неправильно:
А правильно вот так:
При этом testMidlet это экземпляр именно тестового мидлета, а не рабочего.
Вот, собственно, и всё. Надеюсь, кому-то это окажется полезным.
А вы пользуетесь какими-то альтернативами SE-шной библиотеки? Что порекомендуете?
Выбор фреймворка
Выбор был невелик. Google сообщил мне, что существуют такие варианты:
- J2MEUnit
- CLDCUnit
- Motorola Gatling
- SonyEricsson Mobile JUnit
- UPD: JMUnit (спасибо habracut)
Я, каюсь, выбрал, не глядя, вариант SE. Из соображений в духе «ну JUnit от SE наверняка должен без проблем работать с эмуляторами SE». Возможно, это был самый неудачный вариант… 8)
Установка
Скачанный архив содержал библиотеки, пример кода и пример тасков ant`а.
Процитирую один из тасков:
<target name="run-with-coverage" >
<java
classname="com.sonyericsson.sdkme.junit.OnDeviceTest"
fork="true" failonerror="true" >
<classpath refid="test-classpath" />
<arg value="--javac:${javac}" />
<arg value="--project-dir:${project-dir}" />
<arg value="--device:SonyEricsson_K750_Emu"/>
<arg value="--compile:true" />
<arg value="--compile-midlet:true" />
<arg value="--coverage:L" />
<arg value="--coverage-report:${project-dir}/coverage.html" />
<arg value="--name:Mobile JUnit Sample Project" />
</java>
<echo message="A coverage HTML report has been written to ${project-dir}/coverage.html" />
</target>
* This source code was highlighted with Source Code Highlighter.
Видно, что вызывается некий класс с разными параметрами. Нигде, кстати, не документированными. Копипаст результатов не дал. Проблема была в bootclasspath. Вдумчивое чтение декомпилированного кода показало, что библиотека кушает параметры вида --<name>:<value>;<name>:<value>… При этом нереально записать в bootclasspath список либов, путь к каждой из которых начинается с C:. И, кстати, пробелы оно воспринимает как разделители наравне с точкой с запятой. Так что, никаких «Program Files». Решилось всё это распаковкой нужых либов в одну директорию и указанием пути к ней в bootclasspath.
После всех поправок вызов java выглядит так:
<java classname="com.sonyericsson.sdkme.junit.OnDeviceTest" fork="true" failonerror="true">
<classpath>
<pathelement path="${env.MJUNIT_HOME}/junit.jar"/>
<pathelement path="${env.MJUNIT_HOME}/mobile-ju-1.0.jar"/>
<pathelement path="${java.home}/lib"/>
</classpath>
<arg value="--project-dir:${basedir}"/>
<arg value="--device:SonyEricsson_K750_Emu"/>
<arg value="--compile:false"/>
<arg value="--compile-midlet:false"/>
<arg value="--coverage:L" />
<arg value="--runmode:${tests.runmode}"/>
<arg value="--coverage-report:${basedir}/coverage.html"/>
<arg value="--name:Stiter Client"/>
<arg value=""--wtk:${env.WTK_HOME}""/>
<arg value="--print-config:on"/>
<arg value="--midlet-under-test:${jarpath}"/>
<arg value="--bootclasspath:"${toString:tests.bcp}""/>
</java>
* This source code was highlighted with Source Code Highlighter.
Использование
После описанных действий тестовый мидлет собирался и запустился. Но тесты падали с ошибками. Лечение же свелось к тому, что не надо создавать в тестах экземпляр своего мидлета. То есть, вот так неправильно:
public void setUp() throws Throwable {
super.setUp();
midlet = new OurMIDlet();
}
* This source code was highlighted with Source Code Highlighter.
А правильно вот так:
public void setUp(MIDlet miDlet) throws Throwable {
super.setUp(miDlet);
testMidlet = miDlet;
OurApplication.setMidletInstance(testMidlet);
}
* This source code was highlighted with Source Code Highlighter.
При этом testMidlet это экземпляр именно тестового мидлета, а не рабочего.
Вот, собственно, и всё. Надеюсь, кому-то это окажется полезным.
А вы пользуетесь какими-то альтернативами SE-шной библиотеки? Что порекомендуете?