【问题标题】:Do I need to create a test version of my factory for unit testing?我需要为我的工厂创建一个测试版本来进行单元测试吗?
【发布时间】:2017-09-29 14:24:28
【问题描述】:

我使用 ShipFactory 创建船舶对象,但我的船舶依赖于我的 Acclerometer 类(只是 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");

但是现在假设我想统一我的船类并且我想模拟这些依赖项。上下文很容易模拟,因为我可以将模拟上下文传递给我的工厂,但我的工厂仍然依赖于加速度计。

对于单元测试,我应该创建一个仅用于测试的新工厂吗?或者使用工厂是否有好处,在我的单元测试中我可以一起放弃工厂并通过将我的模拟传递给船舶构造函数来直接创建新船。

【问题讨论】:

  • 澄清一下:你要单元测试Ship还是ShipFactory

标签: java android unit-testing dependency-injection factory


【解决方案1】:

您的 ShipFactory 取决于 Ship。但是Ship 不依赖于ShipFactory。独立于ShipFactory 测试您的Ship。既然没有依赖,也就不需要依赖注入了。

现在,当您的工厂变得更大时,您应该专门为您的工厂编写测试。为此,我建议提取所有依赖项并将它们注入到构造函数中。您可以重载构造函数来帮助您:

// 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);
    }
}

【讨论】:

  • 啊,是的,我什至没有考虑过超载。这是我遗漏的一个重要概念。像 spring 这样的 DI 框架会让这更容易吗?
  • 你不需要重载框架,但你仍然需要提取依赖项
【解决方案2】:

从您的代码中,您的 Ship 类公开了一个公共构造函数,因此您不需要 ShipFactory 来创建 Ship 对象。请改用公共 Ship 构造函数并模拟出依赖项。

【讨论】:

  • “你的 Ship 类公开了一个公共构造函数”你不知道。它可能是包私有的
  • @TimCastelijns 好点 :) 但是从 或者使用工厂是否有好处,在我的单元测试中我可以一起放弃工厂并通过我的模拟直接创建一艘新船在船舶构造函数中。 我想我是对的
  • 所以我的班级现在很小,工厂做的不多,但它最终会有一些逻辑根据shipType返回一艘不同的船(猜猜不清楚)。我还需要一个工厂。我的问题更多是关于尝试在这里围绕 DI 和单元测试进行思考
【解决方案3】:

您可以从 ShipFactory 中移除显式 Accelerometer 依赖项,并像使用 Context 对象一样将其传入。

1) 创建一个 AccelerometerFactory,它在其构造函数中接受 Context,以生成一个 Accelerometer

2) 修改 ShipFactory 构造函数以接受 Context 和 Accelerometer,或者您可以修改 makeShip 方法以接受 Accelerometer。

现在您可以分别模拟 Context 和 Accelerometer 并将它们传递给您的 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");
}

【讨论】:

  • 请尝试编写最少的代码来解决问题。
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多