在单元测试环境下SecurityBaseModule.getSecuityModuleRef()返回null,因此尝试创建AuthorizationService会抛出NullPointerException异常。
重构办法:
通过构造函数的参数传入依赖对象,而不自己创建。
使用被测对象的地方负责创建依赖对象。随着重构进行把这一责任不断上推。
把初始化动作与构造函数分开,构造函数只用于获得依赖关系。如果还需要更复杂的初始化动作,在单独的初始化函数中进行。
重构目标:
通过调用构造函数、传入null作为依赖对象引用,能在单元测试中创建被测对象。
无法在测试环境中运行被测方法
如果被测方法在计算过程中自己尝试获得所需的依赖对象,就可能在单元测试环境下因无法满足依赖对象的要求而导致测试失败,从而无法对希望测试的方法进行单元测试。例如SessionManager.isAdminGroupUser方法如下:
在单元测试环境下RpcInvoker的调用尝试必定会抛出异常,于是对isAdminGroupUser方法的调用必定会返回false。如果让RpcInvoker通过网络进行真实的RPC调用,不仅工作量大,使测试不可靠,而且这样的测试实际上主要是在测RpcInvoker的工作是否正确,变成了集成测试而不是SessionManager的单元测试。
重构办法:
通过构造函数的参数传入依赖对象并保存在成员变量中,需要使用依赖对象时通过成员变量调用。被测方法不直接创建依赖对象。
使用被测对象的地方负责创建依赖对象。随着重构进行把这一责任不断上推。
单元测试中用mock框架(推荐JMock)创建依赖对象。在每个测试案例(即测试方法)中独立设置对mock对象的期望,发现明显的重复时再抽取公共代码。
重构目标:
通过调用构造函数、传入mock对象,能在单元测试中创建被测对象。
对mock对象设置适当的期望,能调用被测方法,并覆盖到正常和异常路径。