I read the solution to How to run a simple JUnit4 test in Android Studio 1.1? and verified my gradle plugin version is greater than 1.1
Right Clicking my junit 4 test class and selecting run gives this error in android studio:
Cannot find class com.me.android.javamodule.MyTestClass
My android proj dir looks like:
In module "app":
src-->main
src-->test-->java-->com.me.android.working contains WorkingTest.java
src-->test-->java-->com.me.android.javamodule contains MyTestClass.java
"javamodule" is a regular java module that the app module depends on, it is a sibling to the "app" module.
I don't think the error is accurate because I copied "MyTestClass.java" into com.me.android.working, which contains WorkingTest.java, a Junit4 test that CAN run. Android Studio still complains with the same error.
Here is MyTestClass.java
package com.me.android.javamodule;
import org.junit.Before;
import org.junit.Test;
public class MyTestClass {
private Solver solver;
#Before
public void init() {
solver = new Solver();
}
#Test
public void testReverse() {
assertTrue(solver.parseStr("woof").equals("foow"));
}
}
This worked for me:
right click src and select New Directory, call it test
do the same for test and call it java
right click java and select New Package to create a new package like com.application. unit test can go here.
Related
I am working on an Android application that will call a .so file created by a different Android NDK application.
I have created the following folder structure in my project and copied over the .so files as seen below:
|--app:
|--|--src:
|--|--|--main
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--libmylib.so
|--|--|--|--|--x86
|--|--|--|--|--|--libmylib.so
I call this library through my application via the following code:
static {
System.loadLibrary("mylib");
}
I then call the method from this shared object via the following code:
String str = stringFromJNI();
This does not work as the program looks for mangled function name as follows:
com.example.androidlibcall.MainActivity.stringFromJNI() where my .so function will be using a different package name and hence a different function name is generated.
I am not really sure what I need to do to call the functions from the external library, I assume I can create my own library and utilize dlopen() to load the external library and make calls to it, but was wondering if there are the other methods to achieve this or not.
My ultimate goal is to be able to create applications that can call pre-existing libraries that are on the mobile device, but since I am new to NDK/Android I am not sure what is the best method for this and have not found good examples to work with.
A lot of the pre-existing similar questions seem to be dealing with older versions of Android Studio that don't seem applicable anymore.
I am using the latest version of Android Studio (3.1.2) with Gradle 4.4 on Windows 7 machine.
Please advise.
Thanks!
Generally speaking, it's not a good idea to have native methods in application's MainActivity, but this should not worry us now that we are forging a workaround.
Assume that your new project has com.example.other.MainActivity.java, and you want to call the native method com.example.androidlibcall.MainActivity.stringFromJNI() from com.example.other.MainActivity.onCreate(). To do this, create a new Java class in your other app:
package com.example.androidlibcall;
public class MainActivity {
public static native String stringFromJNI();
}
and in your existing MainActivity class,
package com.example.other;
import static com.example.androidlibcall.MainActivity.stringFromJNI;
class MainActivity {
static {
System.loadLibrary("mylib");
}
}
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
String qq = stringFromJNI();
…
}
}
You see that com/example/androidlibcall/MainActivity.java contains no logic, no data, no code. It is only a wrapper that lets us easily use libmylib.so without rebuilding it.
I am using Android Studio 3.0 beta 2, converted an existing project to gradle plugin 3.0.0-beta2
When I try to run an existing unit test written in kotlin I get 'java.lang.NoClassDefFoundError: com/other/domain/CollectionItem'
The test itself is very simple:
import org.junit.Test
import org.junit.Assert.*
class CollectionViewModelTest {
#Test
fun getItemsWithManyItemsWillReturnCollectionItemViewModels() {
val collectionItems = listOf(CollectionItem(42, "Item1", CollectionItemType.COLLECTION, ""), CollectionItem(43, "Item2", CollectionItemType.COLLECTION, ""), CollectionItem(44, "Item3", CollectionItemType.COLLECTION, ""))
val collection = Collection(45, "Home", "Home collection", collectionItems, 42)
val collectionViewModel = CollectionViewModel(collection)
assertTrue(collectionViewModel.items.first().isFirst)
assertFalse(collectionViewModel.items.first().isLast)
assertFalse(collectionViewModel.items[1].isFirst)
assertFalse(collectionViewModel.items[1].isLast)
assertTrue(collectionViewModel.items.last().isLast)
assertFalse(collectionViewModel.items.last().isFirst)
}
}
It works when I run it from the terminal using ./gradlew
Any ideas why this can happen?
Edit:
This seems to happen only when the test requires classes from other library projects.
In this case CollectionItem is part of another library in the same project and it's included in the gradle file via implementation project(':domain')
Edit
It might also be worth mentioning that domain module is pure java
Edit
Figured out the problem is when the library (domain) has classes written in kotlin, those classes will throw NoClassDefFoundError in unit test's only.
I am using newest version of android studio gradle plugin 1.2.3. I am unable to understand how to create unit tests in it; all the available answers are for older version of android. Help me.
first of all you need a different folder structure for your unit tests.
android studio automatically generats the androidTest folder for instrumentation tests, but you can't put your unit tests in there. so you have to create a "test" folder:
- src
-- androidTest //for instrumentation tests
-- main //source code
-- test //for unit tests
use the same package structure for your tests as for the class you want to test.
you can switch in your build variants of android studio between Android Instrumentation Tests and Unit Tests.
depending on your selection test or androidTest folder will be show in your project tab.
finally you have to add junit to your dependencies in gradle:
dependencies {
testCompile 'junit:junit:4.12'
}
the test classes in your test folder can for example look like this:
package package.of.class.to.test
import org.junit.Before;
import org.junit.Test;
...
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class TestSomething{
#Before
public void setup(){
// test setup
}
#Test
public void testSomething(){
// your unit tests like these simple examples
assertThat(anyBooleanResult, is(expectedBooleanResult));
assertEquals(anyIntResult, expectedIntResult);
}
}
for further information you can also take a look on this thread.
I have this project structure:
/src
/it
/java
/com/xxx/test/it
ContextSteps
/inventory
InventoryIT
InventorySteps
/resources
/com/xxx/test/it/inventory
1.feature
2.feature
Runner InventoryIT (both features are annotated with #inventory)
#RunWith(Cucumber.class)
#CucumberOptions(tags = "#inventory")
public class InventoryIT {
}
Note that ContextSteps in injected in InventorySteps through cucumber-picocontainer.
When I execute project tests through this runner (with maven or from the IDE as well), I expect both 1.feature and 2.feature run (because both are placed in the same resources package), but just runs the first one: 1.feature.
Am I missing something?
Thanks for the help.
Still wondering why is just running one of the two features... can be fixed setting manually the features resources path:
features = "src/it/resources/com/xxx/test/it/inventory")
through #CucumberOptions annotation in the InventoryIT runner.
#RunWith(Cucumber.class)
#CucumberOptions(tags = "#inventory", features = "src/it/resources/com/xxx/test/it/inventory")
public class InventoryIT {
}
Making this change, both feature run.
I want to use one native library for a plurality of applications. Library has compiled through android build system and now located in /system/lib/. It can be loaded in application through System.LoadLibrary("libexample"). But method in library which should be declared like
JNIEXPORT jstring JNICALL Java_application1_MainActivity_method1
turning out unusable because library should be used by several applications. And of course this several applications have their own unique names. So I tried to named my method just like
JNIEXPORT jstring JNICALL method1
and call
public native String method1(String string);
But of course my application trying to find it as Java_application1_MainActivity_method1
How to call this method or how it should be named?
Updated:
I tried to use this(see post with green tick) tutorial to complete my project. I wrote
a library for using native method:
package com.example.mylib;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MyClass extends Activity {
public native static String MyMethod(String string);
static {
System.loadLibrary("nativeLibrary");
}
}
Then I trying to use it in my application:
// Some no interesting inclusions
import com.example.mylib.MyClass;
public class MainActivity extends ListActivity {
// Some no interesting code.
MyMethod(file.getAbsolutePath())
//Some no interesting code
}
And it working as I need! But now I confused that my import com.example.mylib.MyClass;
"never used" in eclipse. And if I will create image with this "Is Library" project the latest will no resolving. Any idea?
Yes, you can use the same JNI signature in many applications. Your class may not belong to the default package of the application, as defined in AndroidManifest.xml. So what?
Example:
Start with HelloJni sample from NDK (in Eclipse, use Import -> Android -> existing Android Code, and point to the ${android-ndk-root}/samples/hello-jni).
Build it and run on device or emulator.
Open a new Android Application project, call it TestCrossJni.
The package name for our app will be: test.cross.jni - no relation to com.example.hellojni!
Choose "Create Activity" -> create Blank Activity.
Add new Java class to this project (src/com/example/hellojni/HelloJni.java):
package com.example.hellojni;
public class HelloJni
{
public static String gets() {
return stringFromJNI();
}
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
private native String stringFromJNI();
/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.hellojni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.load("/data/data/com.example.hellojni/lib/libhello-jni.so");
}
}
Edit res/layout/activity_main.xml: replace
line 12 android:text="#string/hello_world" />
with android:id="#+id/hello_world" />
In src/test/cross/jni/MainActivity.java, add the following after
line 12 setContentView(R.layout.activity_main);
((android.widget.TextView)findViewById(R.id.hello_world)).setText(com.example.hellojni.HelloJni.gets());
Profit!