我使用 ShipFactory 创建船舶对象,但我的船舶依赖于我的 Accelerometer 类(只是 Android 加速度计的包装器)。所以我有我的工厂,当它建造一艘船时,将加速度计传递给船舶建造者。
这是我的 ShipFactory:
public class ShipFactory {
private int screenX;
private int screenY;
private Context context;
private Bitmap bitmap;
// How can I mock this from in my factory?
private Accelerometer accel;
private Ship ship;
public ShipFactory(Context context){
this.context = context;
accel = new Accelerometer(context);
}
public Ship makeShip(String shipType){
bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.myship)
ship = new Ship(context,screenX,screenY,bitmap,accel);
return ship;
}
}
所以我造了一艘这样的船:
ShipFactory shipFactory = new ShipFactory(context);
ship = shipFactory.makeShip("enemy");
但是现在假设我想要合并我的船舶类并且我想要模拟这些依赖关系。上下文很容易模拟,因为我可以将模拟上下文传递给我的工厂,但我的工厂仍然依赖于加速度计。
对于单元测试,我应该创建一个新工厂只是为了测试吗?或者使用工厂的一个好处是,在我的单元测试中我可以完全放弃工厂并通过将我的模拟传递给船舶构造函数来直接创建一艘新船?
您的
ShipFactory
取决于 Ship
。然而 Ship
并不依赖于 ShipFactory
。独立于 Ship
测试您的 ShipFactory
。由于没有依赖关系,因此不需要依赖注入。
现在,当你的工厂变得更大时,你应该专门为你的工厂编写测试。为了实现这一目标,我建议提取所有依赖项并在构造函数中“注入”它们。您可以重载构造函数来帮助您解决此问题:
// you can use this for convenience
public ShipFactory(Context context){
this(new BitmapProvider(context), new Accelerometer(context));
}
// use this for testing because you can provide mock versions
public ShipFactory(BitmapProvider provider, Accelerometer accel){
this.provider = provider;
this.accel = accel;
}
// wrapping BitmapFactory because it is a buncha static methods... aka a pain to mock
class BitmapProvider {
Context context;
public BitmapProvider(Context context){
this.context = context;
}
public Bitmap getBitmap(int resId){
return BitmapFactory.decodeResource(context.getResources(), resId);
}
}
Ship
类公开了一个公共构造函数,因此您不需要
ShipFactory
来创建 Ship
对象。请改用公共 Ship
构造函数并模拟依赖项。1)创建一个 AccelerometerFactory,它在其构造函数中接受 Context,以生成 Accelerometer
2) 修改 ShipFactory 构造函数以接受上下文和加速计,或者您可以修改 makeShip 方法以接受加速计。
现在您可以分别模拟上下文和加速度计并将它们传递给您的 ShipFactory。
public class AccelerometerFactory {
private Context context;
public AccelerometerFactory(Context context){
this.context = context;
}
public Accelerometer makeAccelerometer(){
return new Accelerometer(context);
}
}
public class ShipFactory {
private int screenX;
private int screenY;
private Context context;
private Bitmap bitmap;
private Accelerometer accel;
private Ship ship;
public ShipFactory(Context context, Accelerometer accelerometer){
this.context = context;
this.accel = accelerometer;
}
public Ship makeShip(String shipType){
bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.myship)
ship = new Ship(context,screenX,screenY,bitmap,accel);
return ship;
}
}
{// Calling code
AccelerometerFactory accelFactory = new AccelerometerFactory(context);
Accelerometer accel = accelFactory.makeAccelerometer(); // Note: Accelerometer class would have to be accessible here, not sure if this is the case for you
ShipFactory shipFactory = new ShipFactory(context, accel);
ship = shipFactory.makeShip("enemy");
}