如何测试返回不允许访问其字段的复杂对象的方法。请考虑此代码段 -
public ResultState getResultState(){
ResultState resultState = new ResultState();
// logic //
this.resultState = resultState; //set parent class field
return resultState;
}
ResultState是一个不允许其大部分方法和字段的对象。 关于如何测试除了以下方法之外的其他方法我还是一无所知:
assertNotNull(object.getResultState()) //the return ResultState is used by other class methods
我的问题很笼统,但我希望它能说明我是多么绝望地想要如何进行测试...感谢您的帮助
答案 0 :(得分:11)
嗯,结果有什么重要意义?据推测,它可以做某事或者它将是一个无用的结果。在这种情况下,将工作代码与损坏代码区分开来的是什么?
(我不是要试图解决这个问题 - 有时真的很难保持紧密的封装,但要有效地测试。有时值得开放一个对象以使测试更容易......)
答案 1 :(得分:5)
这个对象做了什么?如果你不能查询字段等,我猜它会对你传入的某个对象起作用吗?如果是这种情况,你可以传入一个实现相同接口的虚拟对象,但检查结果对象是否使用适当的参数,按预期的顺序等调用它。?
e.g。
public class ResultObject {
public void actOn(ActedUpon obj) {
// does stuff
其中ActedUpon
是一个接口,并且具有“正常”实现,并且验证实现(使用像JMock这样的模拟框架将是理想的)
答案 2 :(得分:2)
首先,按照惯例,吸气剂不应该有副作用。这样做几乎肯定是一个坏主意
this.resultState = resultState;
在你的吸气器中。
那就是说,返回resultState必须有一些的目的,否则你为什么要返回呢?因此,请测试resultState是否执行了它应该做的事情。
答案 3 :(得分:2)
基于该代码。我会说检查Not Null就足够了。检查返回的ResultState的功能属于ResultState的测试。您正在尝试测试getResultState()的功能。它唯一能做的就是创建一个新对象并在this.resultState中保存对它的引用。因此,检查它是否创建了一个并查看它是否保存了引用。
答案 4 :(得分:2)
遗憾的是,您正在使用getResultState()
来创建ResultState
对象本身,这实际上是您的阻止程序。考虑重构到以下界面:
protected ResultState initResultState ( )
{
this.resultState = new ResultState();
// Initialization Logic...
return this.resultState;
} // END initResultState
public ResultState getResultState ( )
{
if ( this.resultState === null )
{
return this.initResultState();
}
return this.resultState;
} // END getResultState()
从这个位置开始,测试你的getter方法会更容易。定义一个后代类,它返回可以被查询的ResultState
的已知initResultState()
存根,即:
/**
* The test fixutre's initResultState() method merely returns a simple Stub of
* the ResultState object, which can be more easily interrogated.
*/
public ResultState initResultState ( )
{
return new Stub_ResultState();
} // END initResultState
当然,这仍然会让您受到保护initResultState()
。考虑以下重构:
protected ResultState initResultState ( ResultState newResultState )
{
this.resultState = newResultState;
// Initialization Logic...
return this.resultState;
} // END initResultState
public ResultState getResultState ( )
{
if ( this.resultState === null )
{
return this.initResultState( new ResultState() );
}
return this.resultState;
} // END getResultState
这允许您覆盖后代类中的getResultState()
方法,以便您可以传递另一个ResultState
Stub对象,以便在之后进行操作和查询,例如:
/**
* The test fixture's getResultState() method always acts as a passthrough for
* initResultState(), which is protected, so that the output of the protected
* method can be interrogated.
*/
public ResultState getResultState ( )
{
return this.initResultState( new Stub_ResultState() );
} // END getResultState
从这个位置,您需要两个测试装置:一个覆盖initResultState()
的行为来测试getter的功能;另一个覆盖getResultState()
的行为来测试initResultState()
的行为。两者都使用Stub_ResultState
类的实例,该实例必然是ResultState
类的后代,但提供对其父对象的内部值的公共访问,以便在单元测试中进行询问。
我希望这是有道理的,但请随时要求澄清。
答案 5 :(得分:0)
如果您想要测试的只是在调用o.setResultState(resultState)之后,您可以使用o.getResultState()获取resultState,测试将非常简单:
ResultState resultState = new ResultState(...);
o.setResultState(resultState);
assertEquals(resultState, o.getResultState());
答案 6 :(得分:0)
通过在getter中执行new,您将致力于ResultState的具体实现。在您当前的情况下,这意味着对其状态不透明的实现。
想象一下,不是新建ResultState,而是从工厂获得它,并且工厂提供了一些替代模拟ResultState的方法,以便您可以验证getResultState()是否正在执行创建它并返回它之间的ResultState对象。
获得该效果的一种简单方法是在可覆盖的方法上分解ResultState的创建。例如,
public ResultState getResultState() {
ResultState resultState = createResultState();
...
protected ResultState createResultState() {
return new ResultState();
}
然后,假设您的Test类在同一个包中,您可以创建一个内联子类来覆盖getResultState()以返回模拟。
虽然这有效,但编写测试是一种脆弱的方式。
另一种方法是走向像
这样的事情public ResultState getResultState() {
ResultState resultState = _resultStateFactory.newResultState();
...
这要求您找出将ResultStateFactory注入对象的适当方法,这是依赖注入框架非常适合的。对于测试,请注入一个工厂,该工厂返回一个模拟的ResultState,该ResultState已经按照适当的期望进行了准备。这会将测试问题减少为“是getResultState()在返回之前正确操作ResultState对象吗?”