如何使用内部对象创建进行 JUnit 测试

How to JUnit Test with internal object creation

所以我有一个 class 结构设置如下:

public class foo {
    private DomainService service;

    //constructor to initialize

    public Fleet someMethod(Car car) {
        Fleet fleet = new Fleet();
        if(car!=null) {
            Plane plane = service.findObjectByID(car);
            plane.setColor(Blue);
            fleet.addPlane(plane);
        }
        return fleet;
    }
}

public class DomainService {
    List<Plane> planes;

    //constructure to initialize

    public Optional<Plane> findObjectByID(Car car) {
        for(Plane plane : planes) {
            if(plane.getID() == car.getID()) {
                return Optional.of(plane);
            }
        }
        return Optional.absent();
    }
}

public class Fleet {
    List<Plane> planes;
    int ID;
    Date serviceDate;
}

当用户登录到应用程序时,会通过 spring 托管 bean 进行大量操作和计算。他们从数据库中提取有关用户的所有信息并将其存储到对象中。在上面的示例中,当用户登录时,飞机列表是根据从数据库中提取的信息填充的。

我的问题是 JUnit 对此进行了测试。我的 JUnit 看起来像这样:

public class fooTest {
    private Foo foo;
    private Car car;

    @Before
    public void setUp() throws Exception {
        foo = new Foo();
    }

    @Test
    public void isBlue() {
        car = new Car;
        car.setID(123);
        Fleet result = foo.someMethod(car);
        assertEquals(Color.BLUE, result.getColor());
    }
}

问题是飞机对象在用户首次登录时被初始化,包括飞机 ID。这是真实世界的 ID,是一串随机数字和字符。因为这是一个测试,所以飞机上没有填充任何真实的东西。即使它填充了真实世界的数据,我也不知道将其设置为什么 ID,因为它们是随机的。

所以每次我尝试执行这个 JUnit 时都会失败,因为 findObjectByID 总是 returns 一个 null。

我一直在研究 mocking 或 ArgumentCaptor,但我是 JUnit 测试的新手,我真的不知道它们是如何工作的,或者它们是否对我的情况有帮助。关于如何解决此问题的任何想法?

您可以 运行 您的测试是否具有 Spring 上下文:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath*:spring-context.xml" })
    public class fooTest {

        @Inject
        private DomainService service;
        [...]

或模拟您的对象,例如使用 Mockito 框架:

    @RunWith(MockitoJUnitRunner.class)
    public class fooTest {

        private Plane plane;

        @Mock
        private DomainService service;

        @Before
        public void setUp() {
            plane = new Plane();
            when(service.findObjectByID(any(Car.class))).thenReturn(plane);
        }
        [...]

不需要一直使用框架,例如:

public class foo 
{
    private final DomainService service;
    private final IFleetFactory fleetFactory;

    public foo(final IFleetFactory factory)
    {
        this.fleetFactory = factory;
    }

    public Fleet someMethod(final Car car) 
    {
        final Fleet fleet = fleetFactory.create();
        final Plane plane = service.findObjectByID(car);
        plane.setColor(Blue);
        fleet.addPlane(plane);
        return fleet;
    }
}

在你的测试中你可以使用一个简单的 Dummy 或 IFleetFactory 的 Mock 实例。

但总的来说我认为你的 class 设计是错误的, 您的方法 someMethod 仅使用来自其他 classes 的方法。 如何使用代码创建构造函数 public Fleet(Car car, IDomainService service) 的 someMethod ,你也没有新的问题......