我有一些我想测试的类,但是从测试的角度来看,我发现底层实体非常复杂,因为entites可以有很多层依赖。
例如,我有一个名为Building
的类,其中Parking
有Car
个,有Engine
个,然后是一个函数建筑物作为参数并检查柴油车是否比汽油更多。这意味着在我的测试中,我需要创建一个Building
,然后附加一个Parking
,我必须附加一个Car
,依此类推。
有没有任何标准的方法来处理深层嵌套的实体?
答案 0 :(得分:1)
如果你正在测试一个需要多种类型对象(即List)的函数来验证计数,那么有几种方法可以解决它。
一种方法是模拟一堆对象来返回值。你应该在每个级别进行嘲弄,所以在Building
级别,你是在嘲笑Parking
,而在Parking
级别,你是在嘲笑{ {1}}秒。
Car
但是,如果您想要更少的模拟方法,也可以使用种子值创建来隔离一个独特的案例。
when(car.getEngineType()).thenReturn(EngineType.DIESEL);
在这种情况下,我们可以使用我们自己定义的一堆真实public class CarTest {
private EngineType DIESEL = EngineType.DIESEL;
@Test
public void testCreate() {
Car car = createWithSeedValue();
Assert.equals(DIESEL, car.getEngine().getEngineType());
}
public Car createWithSeedValue() {
return create(EngineTest.createWithSeedValue(DIESEL));
}
public Car create(Engine engine) {
Car car = new Car(engine);
return car;
}
}
POJO填充车库,而不是创建一堆模拟Car
,只提供我们需要的种子值用于处理实际对象的测试。这样做的好处是,您可以更轻松地使用实际POJO实例化列表,而不必模拟传递到列表中的单个对象。
答案 1 :(得分:0)
创建单元测试的“标准方式”(即,如果您只想测试Building
的功能而不是整体测试 - 那将是集成测试)对于具有许多/深度依赖性的对象正在使用mocks
模拟是具有有限功能的虚拟对象(只需执行给定测试所需的操作)。通常,模拟对象的每个方法都知道期望什么输入,并且您提供这些输入与输出之间的手写映射。然后将这些注入到测试对象中而不是实际的依赖项中。
有许多框架可以帮助您创建模拟对象。
答案 2 :(得分:0)
取决于你想要测试的内容,如果你被视为一个单位'。如果提到的所有类都非常强耦合,您可以认为它们是一个单元并一起测试它们。
你也可以考虑调用Builder类一个单元,停放类另一个单元等。在这种情况下,你可以引入mockito框架。
您将一个模拟的Parking对象传递给您的Building类(您正在测试的类)。
我更愿意保留我的单位'小的,通常仅存在一类,或者有时是多个小类。如果你保持你的单位小,你经常需要一个模拟框架来让你的测试集中在那些小单位上。
答案 3 :(得分:0)
您可以使用像Mockito这样的模拟框架。然后,您可以模拟您的类的直接依赖项,并要求依赖项返回您的类可以使用的结果。
与您的方案相关的示例类似于
class Building {
Building(Parking parking) {
//init
}
boolean hasMoreDieselCars() {
return parking.getDieselCarCount() > parking.getPetrolCarCount();
}
}
使用模拟,你可以写这样的东西。
when(parking.getDieselCarCount()).thenReturn(14);
when(parking.getPetrolCarCount()).thenReturn(11);
同样,对于依赖于Parking
列表的单元测试Car
,您可以像这样模拟Car
。
when(car.getEngine()).thenReturn(new DieselEngine());
希望这有帮助。
答案 4 :(得分:0)
工厂是处理这种情况的好方法(嘲笑在这里肯定是一种矫枉过正的行为):
class ObjectFactory {
public static Building building() {
return new Building(parking());
}
public static Parking parking() {
Parking parking = new Parking();
parking.addCar(car());
return parking;
}
public static Car car() {
return new Car(engine());
}
public static Engine engine() {
return new Engine();
}
}
结合数据随机化,您可以每次创建不同(但有效)的对象(这可以增加覆盖范围)。 E.g。
public static Parking parking() {
Parking parking = new Parking();
for(int i = 0; i < integer(1, 10); i++) parking.addCar(car());
return parking;
}
public static Car car() {
Car car = new Car(engine());
car.setModel(alphanumeric(1, 10));
return car;
}
我有时甚至会将这些方法添加到实体类本身。是的,是的 - 它是生产代码中的仅测试代码,但它看起来非常易读,随机化也描述了可以简化对业务逻辑的理解的业务规则。最终代码如下:Parking parking = Parking.random()
。
如果您需要填充不同风格的对象,可以选择以下几种方法:
random()
,randomNoAssociations()
等。有时你需要那些持久存储在DB中的工具 - 然后创建一个单独的工厂(PersistedObjectFactory),它使用原始工厂来创建对象,然后它将存储它们。
PS:在随机化之前的例子中我使用Qala Datagen(免责声明 - 我是作者)。