尝试对一个调用Realm(0.87.4)的类进行单元测试,测试设置失败,
java.lang.NoClassDefFoundError: rx/Observable$OnSubscribe
at io.realm.RealmConfiguration$Builder.<init>(RealmConfiguration.java:279)
at org.testapp.db.MyClassTest.setUp(MyClassTest.java:34)
...
Caused by: java.lang.ClassNotFoundException: rx.Observable$OnSubscribe
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
我的测试课程以:
开头@RunWith(MockitoJUnitRunner.class)
public class MyClassTest extends TestCase {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
Realm realm;
@Before
public void setUp() throws Exception {
File tempFolder = testFolder.newFolder("realmdata");
RealmConfiguration config = new RealmConfiguration.Builder(tempFolder).build();
realm = Realm.getInstance(config);
}
...
我的朋友有:
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:1.10.19"
testCompile "org.robolectric:robolectric:3.0"
compile 'io.realm:realm-android:0.87.4'
如何解决这个问题?
===编辑1 ===
我加入了我的gradle:
testCompile 'io.reactivex:rxjava:1.1.0'
和
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
新错误
java.lang.UnsatisfiedLinkError: no realm-jni in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)
at java.lang.Runtime.loadLibrary0(Runtime.java:849)
at java.lang.System.loadLibrary(System.java:1088)
at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:117)
答案 0 :(得分:8)
在您正在测试的课程中使用Realm时,单元测试很难或不可能(感谢Dmitry提及)。我能做的就是将测试作为仪器测试(感谢Dmitry,Christian)。
这很容易,我不需要改变任何测试方法...
一个。将测试类移动到&#34; androidTest&#34;文件夹,而不是&#34; test&#34;。 (从Android Studio 1.1开始,您应该将/ src / test和Android Instrumentation测试中的单元测试放在/ src / androidTest中)
B中。在gradle构建文件中添加工具测试的依赖项,使用&#34; androidTest&#34;因为他们是工具性的:
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'io.reactivex:rxjava:1.1.0'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'com.android.support:support-annotations:23.1.1'
℃。在测试类中,用AndroidJUnit4替换顶部的跑步者:
@RunWith(AndroidJUnit4.class)
public class MyClassTest extends TestCase {
...
创建类型&#34; Android Tests&#34;的Android运行配置,运行它,瞧,它现在将测试相同的方法,但在设备上。让我很开心。
答案 1 :(得分:2)
从Realm 0.87开始,您还需要将RxJava包含在依赖项中:
compile 'io.reactivex:rxjava:1.1.0'
答案 2 :(得分:0)
官方测试显示了如何执行此操作。在instrumentation tests seem easy(如您所知)中,unit test are quite involved:
@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) @SuppressStaticInitializationFor("io.realm.internal.Util") @PrepareForTest({Realm.class, RealmConfiguration.class, RealmQuery.class, RealmResults.class, RealmCore.class, RealmLog.class}) public class ExampleActivityTest { // Robolectric, Using Power Mock https://github.com/robolectric/robolectric/wiki/Using-PowerMock @Rule public PowerMockRule rule = new PowerMockRule(); private Realm mockRealm; private RealmResults<Person> people; @Before public void setup() throws Exception { // Setup Realm to be mocked. The order of these matters mockStatic(RealmCore.class); mockStatic(RealmLog.class); mockStatic(Realm.class); mockStatic(RealmConfiguration.class); Realm.init(RuntimeEnvironment.application); // Create the mock final Realm mockRealm = mock(Realm.class); final RealmConfiguration mockRealmConfig = mock(RealmConfiguration.class); // TODO: Better solution would be just mock the RealmConfiguration.Builder class. But it seems there is some // problems for powermock to mock it (static inner class). We just mock the RealmCore.loadLibrary(Context) which // will be called by RealmConfiguration.Builder's constructor. doNothing().when(RealmCore.class); RealmCore.loadLibrary(any(Context.class)); // TODO: Mock the RealmConfiguration's constructor. If the RealmConfiguration.Builder.build can be mocked, this // is not necessary anymore. whenNew(RealmConfiguration.class).withAnyArguments().thenReturn(mockRealmConfig); // Anytime getInstance is called with any configuration, then return the mockRealm when(Realm.getDefaultInstance()).thenReturn(mockRealm); // Anytime we ask Realm to create a Person, return a new instance. when(mockRealm.createObject(Person.class)).thenReturn(new Person()); // Set up some naive stubs Person p1 = new Person(); p1.setAge(14); p1.setName("John Young"); Person p2 = new Person(); p2.setAge(89); p2.setName("John Senior"); Person p3 = new Person(); p3.setAge(27); p3.setName("Jane"); Person p4 = new Person(); p4.setAge(42); p4.setName("Robert"); List<Person> personList = Arrays.asList(p1, p2, p3, p4); // Create a mock RealmQuery RealmQuery<Person> personQuery = mockRealmQuery(); // When the RealmQuery performs findFirst, return the first record in the list. when(personQuery.findFirst()).thenReturn(personList.get(0)); // When the where clause is called on the Realm, return the mock query. when(mockRealm.where(Person.class)).thenReturn(personQuery); // When the RealmQuery is filtered on any string and any integer, return the person query when(personQuery.equalTo(anyString(), anyInt())).thenReturn(personQuery); // RealmResults is final, must mock static and also place this in the PrepareForTest annotation array. mockStatic(RealmResults.class); // Create a mock RealmResults RealmResults<Person> people = mockRealmResults(); // When we ask Realm for all of the Person instances, return the mock RealmResults when(mockRealm.where(Person.class).findAll()).thenReturn(people); // When a between query is performed with any string as the field and any int as the // value, then return the personQuery itself when(personQuery.between(anyString(), anyInt(), anyInt())).thenReturn(personQuery); // When a beginsWith clause is performed with any string field and any string value // return the same person query when(personQuery.beginsWith(anyString(), anyString())).thenReturn(personQuery); // When we ask the RealmQuery for all of the Person objects, return the mock RealmResults when(personQuery.findAll()).thenReturn(people); // The for(...) loop in Java needs an iterator, so we're giving it one that has items, // since the mock RealmResults does not provide an implementation. Therefore, anytime // anyone asks for the RealmResults Iterator, give them a functioning iterator from the // ArrayList of Persons we created above. This will allow the loop to execute. when(people.iterator()).thenReturn(personList.iterator()); // Return the size of the mock list. when(people.size()).thenReturn(personList.size()); this.mockRealm = mockRealm; this.people = people; } @Test public void shouldBeAbleToAccessActivityAndVerifyRealmInteractions() { doCallRealMethod().when(mockRealm).executeTransaction(Mockito.any(Realm.Transaction.class)); // Create activity ExampleActivity activity = Robolectric.buildActivity(ExampleActivity.class).create().start().resume().visible().get(); assertThat(activity.getTitle().toString(), is("Unit Test Example")); // Verify that two Realm.getInstance() calls took place. verifyStatic(times(2)); Realm.getDefaultInstance(); // verify that we have four begin and commit transaction calls // Do not verify partial mock invocation count: https://github.com/jayway/powermock/issues/649 //verify(mockRealm, times(4)).executeTransaction(Mockito.any(Realm.Transaction.class)); // Click the clean up button activity.findViewById(R.id.clean_up).performClick(); // Verify that begin and commit transaction were called (been called a total of 5 times now) // Do not verify partial mock invocation count: https://github.com/jayway/powermock/issues/649 //verify(mockRealm, times(5)).executeTransaction(Mockito.any(Realm.Transaction.class)); // Verify that we queried for Person instances five times in this run (2 in basicCrud(), // 2 in complexQuery() and 1 in the button click) verify(mockRealm, times(5)).where(Person.class); // Verify that the delete method was called. Delete is also called in the start of the // activity to ensure we start with a clean db. verify(mockRealm, times(2)).delete(Person.class); // Call the destroy method so we can verify that the .close() method was called (below) activity.onDestroy(); // Verify that the realm got closed 2 separate times. Once in the AsyncTask, once // in onDestroy verify(mockRealm, times(2)).close(); }