如何使用内部对象创建进行 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 ,你也没有新的问题......
所以我有一个 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 ,你也没有新的问题......