Intereting Posts
Как андроид обрабатывает события GUI? Android NDK в Eclipse :: (Не удается запустить программу «ndk-build»: неизвестная причина) Положение MediaController внутри фрагмента Рендеринг проблем с использованием нового TextInputLayout для EditText Реализовать расширенный просмотр Android-ресайклеров с помощью липких заголовков, функцией поиска, алфавитным селектором боковой стороны и элементами / картами Swipable? Направление рисования холста Google Play Services делает apk слишком большим Перекрытие RecyclerView без тени Где драйвер ADB для Windows? Есть ли функция в Android, аналогичная функции «int main» в C / C ++, которая содержит основной цикл программы? Android.content.res.Resurces $ NotFoundException: Идентификатор ресурса строки # 0x0 Как я могу воспроизвести встроенный видеоролик html5 в WebView? Существуют ли какие-либо огромные различия между объектами-c и Java, или iPhone и Android? Не удалось разрешить Landroid / support / v7 / app / AppCompatDelegateImplV7 Как проверить, видна ли активность? OnResume недостаточно

Тестирование Android-модуля с использованием проекта ant с библиотекой

Похоже, что и последние инструменты SDK для Android все равно не поддерживают тестирование приложений, содержащих связанные проекты библиотек.

У меня есть проект со следующей настройкой:

TestLib (проект библиотеки Android) <- TestMain (проект android) <- TestMainTest (проект тестирования блока Android)

Я создал все эти проекты в eclipse, а затем использовал android update (test-/lib-)project ... для создания build.xml et. и др.

Проблема начинается, как только у вас есть класс в TestMain ( InheritAddition.java в моем примере), который наследуется от класса в TestLib ( Addition.java ), и вы хотите ссылаться на этот класс в модульном тесте ( InheritAdditionTest.java ).

TestLib

 public class Addition { public int add2(int o1, int o2) { return o1 + o2; } } 

TestMain

 public class InheritAddition extends Addition { public int sub(int p1, int p2) { return p1 - p2; } } 

TestMainTest

 public class InheritAdditionTest extends AndroidTestCase { public void testSub() { Assert.assertEquals(2, new InheritAddition().sub(3, 1)); } } 

При построении в командной строке результат следующий:

 W / ClassPathPackageInfoSource (14871): вызвано: java.lang.NoClassDefFoundError: org / test / main / InheritAddition
 W / ClassPathPackageInfoSource (14871): ... еще 26
 W / ClassPathPackageInfoSource (14871): вызвано: java.lang.IllegalAccessError: класс ref в предварительно проверенном классе разрешен к непредвиденной реализации
 W / ClassPathPackageInfoSource (14871): в dalvik.system.DexFile.defineClass (собственный метод)
 W / ClassPathPackageInfoSource (14871): at dalvik.system.DexFile.loadClassBinaryName (DexFile.java:195)
 W / ClassPathPackageInfoSource (14871): в dalvik.system.DexPathList.findClass (DexPathList.java:315)
 W / ClassPathPackageInfoSource (14871): в dalvik.system.BaseDexClassLoader.findClass (BaseDexClassLoader.java:58)
 W / ClassPathPackageInfoSource (14871): в java.lang.ClassLoader.loadClass (ClassLoader.java:501)
 W / ClassPathPackageInfoSource (14871): в java.lang.ClassLoader.loadClass (ClassLoader.java:461)
 W / ClassPathPackageInfoSource (14871): ... еще 26
 W / dalvikvm (14871): класс разрешен неожиданным DEX: Lorg / test / main / InheritAddition; (0x41356250): 0x13772e0 ref [Lorg / test / lib / Addition;] Lorg / test / lib / Дополнение; (0x41356250): 0x13ba910

Я нашел некоторое обходное решение, которое работает для eclipse:

Не удается создать и запустить проект тестирования Android, созданный с помощью «ant create test-project», когда тестируемый проект имеет банки в каталоге libs

Это делает трюк, но я ищу решение, которое работает с ANT (точнее, я ищу решение, которое работает на обоих одновременно).

Документированный подход (путем изменения build.xml для включения баков из основного проекта в путь к классу) здесь не применим, так как примерный проект не использует никаких библиотек (также я считаю, что эта конкретная проблема теперь исправлена ​​с помощью инструментов SDK r16).

Я предполагаю, что для решения этой проблемы необходимо попытаться каким-то образом удалить зависимости TestMainTest с TestLib (путем изменения project.properties ) и вместо этого удастся взломать скрипт сборки, чтобы поместить эти встроенные банки в путь класса (так что замените -compile цель с чем-то, что изменяет путь класса для javac ). Поскольку у меня есть долгая история, пытаясь идти в ногу с изменениями привязки Android SDK, это не мой любимый вариант, поскольку он a) довольно сложный и b) требует постоянной модификации build.xml всякий раз, когда изменяется цепочка инструментов (что вполне часто).

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

Solutions Collecting From Web of "Тестирование Android-модуля с использованием проекта ant с библиотекой"

Ответ @ wallacen60 хорош. Вчера я пришел к такому же выводу. Тем не менее, существует еще один вариант: вместо исключения бана lib из dexing тестового проекта, было бы неплохо, если бы мы могли найти способ включить банку lib в компиляцию (javac, этап компиляции файла ant) Тест и только на стадии компиляции, а не на стадии дезинфекции.

Кроме того, решение @ wallacen60 вводит большую смысловую разницу между компиляцией проекта 3 и их зависимостями: в приложении Eclipse зависит от lib, тест зависит от приложения. И это правильный способ сделать это. Но в ant, как App, так и Test зависят от Lib и кажутся плохим циклом redunduncy для меня.

Итак, на данный момент мы сделали попытку исправить файл project.properties тестового проекта, чтобы он включал эту строку:

 tested.android.library.reference.1=../SDK_android 

И мы модифицировали файл ant тестируемого проекта, так что цель компиляции включает в себя библиотеку: (посмотрите на измененную строку, найдите слово «change»).

  <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries --> <!-- Compiles this project's .java files into .class files. --> <target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- If android rules are used for a test project, its classpath should include tested project's location --> <condition property="extensible.classpath" value="${tested.project.absolute.dir}/bin/classes" else="."> <isset property="tested.project.absolute.dir" /> </condition> <condition property="extensible.libs.classpath" value="${tested.project.absolute.dir}/${jar.libs.dir}" else="${jar.libs.dir}"> <isset property="tested.project.absolute.dir" /> </condition> <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="android.target.classpath" verbose="${verbose}" classpath="${extensible.classpath}" classpathref="jar.libs.ref"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <classpath> <!-- steff: we changed one line here !--> <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/> <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> </classpath> <compilerarg line="${java.compilerargs}" /> </javac> <!-- if the project is instrumented, intrument the classes --> <if condition="${build.is.instrumented}"> <then> <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo> <!-- It only instruments class files, not any external libs --> <emma enabled="true"> <instr verbosity="${verbosity}" mode="overwrite" instrpath="${out.absolute.dir}/classes" outdir="${out.absolute.dir}/classes"> </instr> <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from user defined file --> </emma> </then> </if> </do-only-if-manifest-hasCode> </target> к  <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries --> <!-- Compiles this project's .java files into .class files. --> <target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- If android rules are used for a test project, its classpath should include tested project's location --> <condition property="extensible.classpath" value="${tested.project.absolute.dir}/bin/classes" else="."> <isset property="tested.project.absolute.dir" /> </condition> <condition property="extensible.libs.classpath" value="${tested.project.absolute.dir}/${jar.libs.dir}" else="${jar.libs.dir}"> <isset property="tested.project.absolute.dir" /> </condition> <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="android.target.classpath" verbose="${verbose}" classpath="${extensible.classpath}" classpathref="jar.libs.ref"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <classpath> <!-- steff: we changed one line here !--> <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/> <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> </classpath> <compilerarg line="${java.compilerargs}" /> </javac> <!-- if the project is instrumented, intrument the classes --> <if condition="${build.is.instrumented}"> <then> <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo> <!-- It only instruments class files, not any external libs --> <emma enabled="true"> <instr verbosity="${verbosity}" mode="overwrite" instrpath="${out.absolute.dir}/classes" outdir="${out.absolute.dir}/classes"> </instr> <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from user defined file --> </emma> </then> </if> </do-only-if-manifest-hasCode> </target> к  <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries --> <!-- Compiles this project's .java files into .class files. --> <target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- If android rules are used for a test project, its classpath should include tested project's location --> <condition property="extensible.classpath" value="${tested.project.absolute.dir}/bin/classes" else="."> <isset property="tested.project.absolute.dir" /> </condition> <condition property="extensible.libs.classpath" value="${tested.project.absolute.dir}/${jar.libs.dir}" else="${jar.libs.dir}"> <isset property="tested.project.absolute.dir" /> </condition> <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="android.target.classpath" verbose="${verbose}" classpath="${extensible.classpath}" classpathref="jar.libs.ref"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <classpath> <!-- steff: we changed one line here !--> <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/> <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> </classpath> <compilerarg line="${java.compilerargs}" /> </javac> <!-- if the project is instrumented, intrument the classes --> <if condition="${build.is.instrumented}"> <then> <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo> <!-- It only instruments class files, not any external libs --> <emma enabled="true"> <instr verbosity="${verbosity}" mode="overwrite" instrpath="${out.absolute.dir}/classes" outdir="${out.absolute.dir}/classes"> </instr> <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from user defined file --> </emma> </then> </if> </do-only-if-manifest-hasCode> </target> к  <!-- override "compile" target in platform android_rules.xml to include tested app's external libraries --> <!-- Compiles this project's .java files into .class files. --> <target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- If android rules are used for a test project, its classpath should include tested project's location --> <condition property="extensible.classpath" value="${tested.project.absolute.dir}/bin/classes" else="."> <isset property="tested.project.absolute.dir" /> </condition> <condition property="extensible.libs.classpath" value="${tested.project.absolute.dir}/${jar.libs.dir}" else="${jar.libs.dir}"> <isset property="tested.project.absolute.dir" /> </condition> <echo message="jar libs dir : ${tested.project.target.project.libraries.jars}"/> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="android.target.classpath" verbose="${verbose}" classpath="${extensible.classpath}" classpathref="jar.libs.ref"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <classpath> <!-- steff: we changed one line here !--> <fileset dir="${tested.android.library.reference.1}/bin/" includes="*.jar"/> <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> </classpath> <compilerarg line="${java.compilerargs}" /> </javac> <!-- if the project is instrumented, intrument the classes --> <if condition="${build.is.instrumented}"> <then> <echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo> <!-- It only instruments class files, not any external libs --> <emma enabled="true"> <instr verbosity="${verbosity}" mode="overwrite" instrpath="${out.absolute.dir}/classes" outdir="${out.absolute.dir}/classes"> </instr> <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from user defined file --> </emma> </then> </if> </do-only-if-manifest-hasCode> </target> 

Действительно, этот механизм кажется правильным, поскольку он имитирует то, что делает затмение. Но eclipse может знать, что приложение зависит от lib при компиляции теста. Единственное различие заключается в том, что мы разоблачили это отношение вручную в ant через строку (в project.properties)

 tested.android.library.reference.1=../SDK_android 

Но это можно сделать автоматически. Я не могу найти механизм, который инструменты google ant используют для создания исправления пути проекта librairy из инструкции android.library. * В project.properties. Но если бы я мог найти этот механизм, я мог бы распространять эту зависимость в тестовом проекте, как это делает eclipse.

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

Может ли кто-нибудь связаться с Google об этой ошибке?

Использование Android SDK Tools r15 и Eclipse.

Предположим, вы создали три проекта в eclipse: Lib (проект библиотеки Android) <- Приложение (проект приложения для Android) <- Тест (проект тестирования модуля Android) и определите следующие классы:

[Lib]

 public class A {} 

[Приложение]

 public class A extends B {} 

[Контрольная работа]

 public class MyUnitTest extends AndroidTestCase { public void test() { new A(); new B(); } } 

В этой установке TestMain ссылается на TestLib как на библиотеку Android, а TestMainTest имеет ссылку на проект TestMain.

Вы должны увидеть, что тест не компилируется, потому что A не может быть разрешен. Это ожидается, потому что Test не имеет видимости в Lib. Одним из решений является добавление ссылки на библиотеку из Test to Lib. Хотя это устраняет проблему компиляции, она ломается во время выполнения. Возникает множество ошибок, но это интересно:

 W/dalvikvm( 9275): Class resolved by unexpected DEX: Lcom/example/B;(0x40513450):0x294c70 ref [Lcom/example/A;] Lcom/example/A;(0x40513450):0x8f600 W/dalvikvm( 9275): (Lcom/example/B; had used a different Lcom/example/A; during pre-verification) W/dalvikvm( 9275): Unable to resolve superclass of Lcom/example/B; (1) W/dalvikvm( 9275): Link of class 'Lcom/example/B;' failed E/dalvikvm( 9275): Could not find class 'com.example.B', referenced from method com.example.test.MyUnitTest.test W/dalvikvm( 9275): VFY: unable to resolve new-instance 3 (Lcom/example/B;) in Lcom/example/test/MyUnitTest; D/dalvikvm( 9275): VFY: replacing opcode 0x22 at 0x0000 D/dalvikvm( 9275): VFY: dead code 0x0002-000a in Lcom/example/test/MyUnitTest;.test ()V 

Это связано с тем, что проекты Test и App ссылаются на проект библиотеки Lib, поэтому оба получаемых apks включают копию com.example.A.

Не добавляйте явные зависимости в eclipse из тестового проекта в проект библиотеки (если эта библиотека является зависимостью тестируемого прикладного проекта). Это может привести к тому, что как приложения, так и тестовые проекты будут включать в себя копии тех же классов в их итоговых апках, и тест будет терпеть неудачу во время выполнения.

Нам нужно найти путь к проблеме видимости времени компиляции. Во время выполнения Test будет иметь видимость в приложении и, следовательно, классы в Lib. Вместо того, чтобы создавать ссылку на библиотеку из Test to Lib, обновите путь сборки приложения для экспорта его библиотечных проектов. Теперь тестовые компиляции и тестовые тесты успешно выполняются.

В Eclipse для тестирования проекта приложения, ссылающегося на проект библиотеки, экспортируйте проекты библиотеки из проекта приложения в его параметры пути сборки.

Сейчас все работает в Eclipse, но что касается Ant? Используйте команды проекта android update [lib- | test-] для создания необходимых файлов build.xml. Не забудьте запустить Ant clean во всех трех каталогах: Lib, App и Test. Неспособность очистить все три проекта может привести к успешной компиляции.

Сбой компиляции Ant:

 [javac] ...Test/src/com/example/test/MyUnitTest.java:3: cannot find symbol [javac] symbol : class A [javac] location: package com.example [javac] import com.example.A; [javac] ^ [javac] ...Test/src/com/example/test/MyUnitTest.java:10: cannot access com.example.A [javac] class file for com.example.A not found [javac] new B(); [javac] ^ [javac] ...Test/src/com/example/test/MyUnitTest.java:11: cannot find symbol [javac] symbol : class A [javac] location: class com.example.test.MyUnitTest [javac] new A(); [javac] ^ [javac] 3 errors 

Почему сборка Ant не работает, когда сборка Eclipse завершается успешно? Системы сборки Eclipse и Ant различны. Экспорт проектов библиотеки из приложения в Eclipse не влияет на сборку Ant. Сбой сборки невозможен, потому что тестовый проект не имеет видимости в проекте Lib. Если мы попытаемся решить эту проблему, добавив свойство android.library.refernce к Test / project.properties, мы сделали то же самое, что и добавление ссылки библиотеки из Test to Lib в Eclipse. Ant build будет успешным, но тест будет терпеть неудачу во время выполнения со знакомой ошибкой класса, разрешенной неожиданным DEX.

Нам нужен способ, чтобы тестовый проект скомпилировался против проекта библиотеки, но не включал его в процесс dexing. Для этого есть два шага. Во-первых, включите ссылку от Test to Lib, которая не влияет на Eclipse. Во-вторых, обновите систему сборки Ant, чтобы библиотека была скомпилирована, но исключена из dexing.

В верхней части Test / build.xml я определяю свойство, которое указывает на библиотеку. Это похоже на добавление ссылки на Test / project.properties, за исключением того, что Eclipse не увидит этого:

Теперь нам нужно исключить библиотечную банку из процесса dexing. Это требует обновления макроса dex-helper. Я помещаю макрос переопределения после строки в файле Test / build.xml. Новый помощник dex исключает все файлы jar не в дереве папок тестового проекта из процесса дексинга:

 <macrodef name="dex-helper"> <element name="external-libs" optional="yes"/> <attribute name="nolocals" default="false"/> <sequential> <!-- sets the primary input for dex. If a pre-dex task sets it to something else this has no effect --> <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}"/> <!-- set the secondary dx input: the project (and library) jar files If a pre-dex task sets it to something else this has no effect --> <if> <condition> <isreference refid="out.dex.jar.input.ref"/> </condition> <else> <!-- out.dex.jar.input.ref is not set. Compile the list of jars to dex. For test projects, only dex jar files included in the project path --> <if condition="${project.is.test}"> <then> <!-- test project --> <pathconvert pathsep="," refid="jar.libs.ref" property="jars_to_dex_pattern"/> <path id="out.dex.jar.input.ref"> <files includes="${jars_to_dex_pattern}"> <!-- only include jar files actually in the test project --> <filename name="${basedir}/**/*"/> </files> </path> <property name="in_jars_to_dex" refid="jar.libs.ref"/> <property name="out_jars_to_dex" refid="out.dex.jar.input.ref"/> <echo message="Test project! Reducing jars to dex from ${in_jars_to_dex} to ${out_jars_to_dex}."/> </then> <else> <path id="out.dex.jar.input.ref"/> </else> </if> </else> </if> <dex executable="${dx}" output="${intermediate.dex.file}" nolocals="@{nolocals}" verbose="${verbose}"> <path path="${out.dex.input.absolute.dir}"/> <path refid="out.dex.jar.input.ref"/> <external-libs/> </dex> </sequential> </macrodef> 

С этими изменениями на месте, Test строит и запускается как из Eclipse, так и из Ant.

Счастливое тестирование!

Другие примечания. Если в Eclipse ничего не строится, и вы уверены, что должны, попробуйте обновить проекты в следующем порядке: Lib, App, Test. Мне часто приходится делать это после изменения пути построения. Мне также иногда приходится строить чистые вещи для правильной работы.

Ответы, размещенные здесь, немного запутаны. Я не уверен, что это было недавно изменено, но в r15 можно просто добавить следующую строку в свои project.properties, и все будет построено. Вам не нужно изменять какие-либо скрипты сборки.

 android.library.reference.1=../lib_project 

Я предполагаю, что он не ищет рекурсивные проекты библиотек, поэтому вам просто нужно ссылаться на него в своем тестовом проекте, если вы ссылаетесь на него в тестируемом проекте.