如何使用RxJava 2中的TestObserver对对象列表进行单元测试?

时间:2017-11-21 00:38:27

标签: java unit-testing observable junit4 rx-java2

这是一个用于持有人物对象的 Person class 。它有可比较的实现进行比较。

public class Person implements Comparable<Person> {

    private String firstName = "";
    private String lastName = "";

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public int compareTo(@NonNull Person person) {
        return this.firstName.compareTo(person.getFirstName());
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

这是一个工厂类,用于创建人员列表和人员列表Observables 。它总是创造同一组人。

import java.util.ArrayList;
import io.reactivex.Observable;

public class PeopleFactory {

    public static ArrayList<Person> createPeople() {
        ArrayList<Person> people = new ArrayList<>();

        for (int i=0; i<10; i++) {
            people.add(new Person("Thanks" + i, "Giving" + i));
        }

        return people;
    }

    public static Observable<ArrayList<Person>> createPersonObservable() {
        return Observable.just(createPeople());
    }
}

现在我想使用RxJava 2中的 TestObserver来测试来自人Observable发布的人员的人员列表

import org.junit.Test;
import java.util.ArrayList;
import io.reactivex.Observable;
import io.reactivex.observers.TestObserver;


public class PersonTest {
    @Test
    public void testPeople() {
        // Creating a people Observable
        Observable<ArrayList<Person>> peopleObservable = PeopleFactory.createPersonObservable();

        // Creating an test observer and subscribe to the above peopleObservable
        TestObserver<ArrayList<Person>> observer = new TestObserver<>();
        peopleObservable.subscribe(observer);

        // Creating the same people list and assert this people list with the people list from the peopleObservable
        ArrayList<Person> people = PeopleFactory.createPeople();
        observer.assertValue(people);
    }
}

我期望这个测试应该通过,因为PeopleFactory正在为普通人列表和人员列表Observable创建相同的一组人,而Person类有一个Comparable,表示该对象与firstName一样长是平等的。

测试忽略了此Comparable,将其与对象地址进行了比较,并给了我以下测试失败消息:

java.lang.AssertionError: Expected: [com.example.myapplication.Person@7006c658, com.example.myapplication.Person@34033bd0, com.example.myapplication.Person@47fd17e3, com.example.myapplication.Person@7cdbc5d3, com.example.myapplication.Person@3aa9e816, com.example.myapplication.Person@17d99928, com.example.myapplication.Person@3834d63f, com.example.myapplication.Person@1ae369b7, com.example.myapplication.Person@6fffcba5, com.example.myapplication.Person@34340fab] (class: ArrayList), Actual: [com.example.myapplication.Person@2aafb23c, com.example.myapplication.Person@2b80d80f, com.example.myapplication.Person@3ab39c39, com.example.myapplication.Person@2eee9593, com.example.myapplication.Person@7907ec20, com.example.myapplication.Person@546a03af, com.example.myapplication.Person@721e0f4f, com.example.myapplication.Person@28864e92, com.example.myapplication.Person@6ea6d14e, com.example.myapplication.Person@6ad5c04e] (class: ArrayList) (latch = 0, values = 1, errors = 0, completions = 1)

    at io.reactivex.observers.BaseTestConsumer.fail(BaseTestConsumer.java:163)
    at io.reactivex.observers.BaseTestConsumer.assertValue(BaseTestConsumer.java:332)
    at com.example.myapplication.PersonTest.testPeople(PersonTest.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)

那么,什么是正确的方法或如何在RxJava 2中使用TestObserver对对象列表进行单元测试?

注意:以上所有代码都是用Android Studio编写的。

2 个答案:

答案 0 :(得分:2)

来自Comparable的javadoc:

  

此接口对实现它的每个类的对象强加一个总排序。 ...   强烈建议,但并非严格要求(x.compareTo(y)== 0)==(x.equals(y))。

Comparable::compareTo方法仅在排序或以其他方式比较元素的顺序时使用。平等是完全独立的,正如您所指出的,对象身份正在被断言。

您可以通过查看来源https://github.com/ReactiveX/RxJava/blob/v2.1.6/src/main/java/io/reactivex/observers/BaseTestConsumer.java#L331

快速确认框架的功能
if (!ObjectHelper.equals(value, v)) {
  throw fail("Expected: " + valueAndClass(value) + ", Actual: " + valueAndClass(v));
}

ObjectHelper::equals

public static boolean equals(Object o1, Object o2) { // NOPMD
  return o1 == o2 || (o1 != null && o1.equals(o2));
}

所以它调用Object::equals你没有为Person类重载,所以测试使用对象标识并按预期失败。

答案 1 :(得分:0)

感谢@ Murka的回答,在我用Comparable

替换@Override public boolean equals(Object obj)实现后,它按预期工作
public class Person {

    private String firstName = "";
    private String lastName = "";

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }


    @Override
    public boolean equals(Object obj) {
        return this.firstName.equalsIgnoreCase(((Person) obj).getFirstName());
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}