如何在简单的游戏设置中正确测试 Android 模型 (MVP)?
How to properly test Android model (MVP) in simple game setup?
我正在做一个简单的游戏,有一些关于模型的问题setup/testing!如果可能的话,我正在尝试遵循 MVP 模式。
以下是我的一些模型classes的简化版本,主要是处理"logic".
的那些
public class GameManager implements LocationManagerDelegate {
private LocationManager mLocationManager;
private BattleManager mBattleManager;
public GameManager(Location initialLocation) {
mLocationManager = new LocationManager(initialLocation, self);
mBattleManager = new BattleManager();
}
public void setLocation(Location location) {
mLocationManager.setLocation(location);
}
public void handleLocationAction(Action action) {
if (action.type == BATTLE) {
mBattleManager.startBattle();
}
}
}
public class LocationManager {
private LocationManagerDelegate mDelegate;
private Location mLocation;
public LocationManager(Location initialLocation, LocationManagerDelegate delegate) {
mLocation = initialLocation;
mDelegate = delegate;
}
public void setLocation(Location location) {
mLocation = location;
Action action = location.getRandomAction();
mDelegate.handleLocationAction(action);
}
}
public interface LocationManagerDelegate {
void handleLocationAction(Action action);
}
public class BattleManager {
public BattleManager() {
}
public void startBattle() {
// Do stuff...
}
}
我有兴趣正确测试这些 classes。我可以轻松测试 LocationManager
和 BattleManager
- 它们是分开的,并且我可以在需要时为代表使用模拟接口(即 LocationManagerDelegate
)
但是 GameManager
呢?它在自己的 class 中创建了具体的 LocationManager
/BattleManager
实例,所以如果我想使用 GameManager
测试 classes 的整体逻辑流程,它实际上将测试 GameManager
以及 LocationManager
/BattleManager
逻辑。我想不出一个干净的方法来拆分它...
也许这样更正确?
public class GameManager implements LocationManagerDelegate {
private ILocationManager mLocationManager;
private IBattleManager mBattleManager;
public GameManager(Location initialLocation, ILocationManager locationManager, IBattleManager battleManager) {
mLocationManager = locationManager;
mLocationManager.setInitialLocation(initialLocation);
mLocationManager.setDelegate(this);
mBattleManager = battleManager;
mBattleManager.setDelegate(this);
}
public void setLocation(Location location) {
mLocationManager.setLocation(location);
}
public void handleLocationAction(Action action) {
if (action.type == BATTLE) {
mBattleManager.startBattle();
}
}
}
public interface ILocationManager {
void setInitialLocation(Location initialLocation);
void setDelegate(LocationManagerDelegate delegate);
void setLocation(Location location);
}
public class LocationManager implements ILocationManager {
private LocationManagerDelegate mDelegate;
private Location mLocation;
public void setInitialLocation(Location initialLocation) {
mLocation = initialLocation;
}
public void setDelegate(LocationManagerDelegate delegate) {
mDelegate = delegate;
}
public void setLocation(Location location) {
mLocation = location;
Action action = location.getRandomAction();
mDelegate.handleLocationAction(action);
}
}
public interface LocationManagerDelegate {
void handleLocationAction(Action action);
}
public interface IBattleManager {
void startBattle();
}
public class BattleManager implements IBattleManager {
public void startBattle() {
// Do stuff...
}
}
然后在我们实际创建 GameManager
实例的任何地方,我们都会做类似的事情:
ILocationManager locationManager = new LocationManager();
IBattleManager battleManager = new BattleManager();
Location initialLocation = ...;
GameManager manager = new GameManager(initialLocation, locationManager, battleManager);
这将允许我放入模拟 LocationManager
/BattleManager
对象,但可能不会太大,因为这也暴露了 [=17] 的 "inner workings" =] class。它不一定是 public 我需要传递给这些其他经理 classes 等的信息...
那么最好做什么呢?有什么想法!
我会说你在这里有两个选择:
1.依赖项的构造函数注入
正如您在上面概述的那样。依赖项在 class 之外创建,并在创建时传入。这样你就可以在测试时传递你的模拟。如果您使用诸如 Dagger 之类的依赖项注入库,这也是您的做法。
2。将依赖包设为私有
由于 class 的测试与 class 本身位于同一个包中,因此它们可以访问包私有变量。在这种情况下,您将更改两个依赖项的访问级别:
public class GameManager implements LocationManagerDelegate {
LocationManager mLocationManager;
BattleManager mBattleManager;
//...
}
然后根据您的测试,您可以执行以下操作:
@Before
public void setUp() throws Exception {
gameManager = new GameManager();
gameManager.mLocationManager = locationMock;
gameManager.mBattleManager = battleMock;
}
这两种方法都需要权衡打开被测 class 的内部。就我个人而言,我目前更喜欢使用构造函数注入,因为我已经为 DI 设置了 classes。
我正在做一个简单的游戏,有一些关于模型的问题setup/testing!如果可能的话,我正在尝试遵循 MVP 模式。
以下是我的一些模型classes的简化版本,主要是处理"logic".
的那些public class GameManager implements LocationManagerDelegate {
private LocationManager mLocationManager;
private BattleManager mBattleManager;
public GameManager(Location initialLocation) {
mLocationManager = new LocationManager(initialLocation, self);
mBattleManager = new BattleManager();
}
public void setLocation(Location location) {
mLocationManager.setLocation(location);
}
public void handleLocationAction(Action action) {
if (action.type == BATTLE) {
mBattleManager.startBattle();
}
}
}
public class LocationManager {
private LocationManagerDelegate mDelegate;
private Location mLocation;
public LocationManager(Location initialLocation, LocationManagerDelegate delegate) {
mLocation = initialLocation;
mDelegate = delegate;
}
public void setLocation(Location location) {
mLocation = location;
Action action = location.getRandomAction();
mDelegate.handleLocationAction(action);
}
}
public interface LocationManagerDelegate {
void handleLocationAction(Action action);
}
public class BattleManager {
public BattleManager() {
}
public void startBattle() {
// Do stuff...
}
}
我有兴趣正确测试这些 classes。我可以轻松测试 LocationManager
和 BattleManager
- 它们是分开的,并且我可以在需要时为代表使用模拟接口(即 LocationManagerDelegate
)
但是 GameManager
呢?它在自己的 class 中创建了具体的 LocationManager
/BattleManager
实例,所以如果我想使用 GameManager
测试 classes 的整体逻辑流程,它实际上将测试 GameManager
以及 LocationManager
/BattleManager
逻辑。我想不出一个干净的方法来拆分它...
也许这样更正确?
public class GameManager implements LocationManagerDelegate {
private ILocationManager mLocationManager;
private IBattleManager mBattleManager;
public GameManager(Location initialLocation, ILocationManager locationManager, IBattleManager battleManager) {
mLocationManager = locationManager;
mLocationManager.setInitialLocation(initialLocation);
mLocationManager.setDelegate(this);
mBattleManager = battleManager;
mBattleManager.setDelegate(this);
}
public void setLocation(Location location) {
mLocationManager.setLocation(location);
}
public void handleLocationAction(Action action) {
if (action.type == BATTLE) {
mBattleManager.startBattle();
}
}
}
public interface ILocationManager {
void setInitialLocation(Location initialLocation);
void setDelegate(LocationManagerDelegate delegate);
void setLocation(Location location);
}
public class LocationManager implements ILocationManager {
private LocationManagerDelegate mDelegate;
private Location mLocation;
public void setInitialLocation(Location initialLocation) {
mLocation = initialLocation;
}
public void setDelegate(LocationManagerDelegate delegate) {
mDelegate = delegate;
}
public void setLocation(Location location) {
mLocation = location;
Action action = location.getRandomAction();
mDelegate.handleLocationAction(action);
}
}
public interface LocationManagerDelegate {
void handleLocationAction(Action action);
}
public interface IBattleManager {
void startBattle();
}
public class BattleManager implements IBattleManager {
public void startBattle() {
// Do stuff...
}
}
然后在我们实际创建 GameManager
实例的任何地方,我们都会做类似的事情:
ILocationManager locationManager = new LocationManager();
IBattleManager battleManager = new BattleManager();
Location initialLocation = ...;
GameManager manager = new GameManager(initialLocation, locationManager, battleManager);
这将允许我放入模拟 LocationManager
/BattleManager
对象,但可能不会太大,因为这也暴露了 [=17] 的 "inner workings" =] class。它不一定是 public 我需要传递给这些其他经理 classes 等的信息...
那么最好做什么呢?有什么想法!
我会说你在这里有两个选择:
1.依赖项的构造函数注入
正如您在上面概述的那样。依赖项在 class 之外创建,并在创建时传入。这样你就可以在测试时传递你的模拟。如果您使用诸如 Dagger 之类的依赖项注入库,这也是您的做法。
2。将依赖包设为私有
由于 class 的测试与 class 本身位于同一个包中,因此它们可以访问包私有变量。在这种情况下,您将更改两个依赖项的访问级别:
public class GameManager implements LocationManagerDelegate {
LocationManager mLocationManager;
BattleManager mBattleManager;
//...
}
然后根据您的测试,您可以执行以下操作:
@Before
public void setUp() throws Exception {
gameManager = new GameManager();
gameManager.mLocationManager = locationMock;
gameManager.mBattleManager = battleMock;
}
这两种方法都需要权衡打开被测 class 的内部。就我个人而言,我目前更喜欢使用构造函数注入,因为我已经为 DI 设置了 classes。