如何在一个方法中编写UT来模拟内部对象?

时间:2011-09-16 06:27:44

标签: java unit-testing

例如,我有一个java类,如下所示。我将为doWork()编写一个单元测试,所以我想控制obj的行为。但很明显,obj是在内部实例化的。

我怎么写这个UT?现在我正在使用Junit + Mockito。

class ToBeTest{
    public ToBeTest(){}
    public boolean doWork(){
        OtherObject obj=new OtherObject();
        return obj.work();
    }
}

提前致谢。 :)

BTW,现实是我正在为其他人的班级写UT。所以我不想改变它。它已通过集成测试进行了全面测试。

6 个答案:

答案 0 :(得分:10)

如果您无法更改代码,可以使用Powermock以及junit和Mockito来模拟新对象的构造。

@Test
public void testDoWork() throws Exception{

    MyTest mytest = new MyTest();

    OtherObj obj = new OtherObj();
    obj.test="mocked Test"; //here you can add any other needed values to obj

    PowerMockito.whenNew(OtherObj.class).withNoArguments().thenReturn(obj);

    String result = mytest.doWork();
    Assert.assertTrue(result.equalsIgnoreCase("mocked Test"));
}

答案 1 :(得分:2)

最好的方法是编写代码以支持测试Test-Driven Development强调这一点)。目前,您的代码是以难以测试的方式编写的。

考虑使用依赖注入,因为它可以帮助您模拟依赖对象。

答案 2 :(得分:1)

你不能轻易。我可以想到两种方法可以做到这一点,据我所知,Mockito或jUnit都不支持开箱即用:

1)使用cglib或类似的库进行字节代码操作,这种方法很难做到并且可能非常脆弱。

2)备用类加载器。您可以构建一个类加载器,查找尝试加载OtherObject类并将其替换为匿名的OtherObject类,该类为您提供所需的模拟行为。

大多数时候你应该将它视为依赖。如果你想测试打开一个文件,你可能真的想用文件测试,所以使用具体的类可能没问题。如果你想测试一个方法的行为,即打开一个文件作为其逻辑的一部分,你可以轻松地将它移到一个依赖项然后模拟它。事实上,这通常是有道理的,因为有一天你在文件中存储的东西,可能需要存储在另一个数据库中,或者在第三天从云中下载,所以将逻辑与你对文件的处理分开无论如何,打开检索内容的实际过程通常是关注点的逻辑分离。

答案 3 :(得分:1)

这是一个经典的例子,你应该使用dependency injection

简而言之,不是在内部创建对象(依赖),而是在构造函数中传递它,或者使用工厂来创建所需的东西(工厂在生产代码中返回真实的实现,在测试中返回另一个)。这使您可以在测试时更改实现。

查看我提供的示例或google的“ Java依赖注入示例”之后的示例。

答案 4 :(得分:1)

这很容易:

import org.junit.*;
import mockit.*;

@Test
public void justMockIt()
{
    new NonStrictExpectations() { OtherObject o; { o.work(); result = true; }};

    assert new ToBeTest().doWork();
}

...使用JMockit时。

答案 5 :(得分:0)

您已编写代码,现在您想对其进行单元测试。这是你遇到困难的根本原因。我建议采用不同的方法。

  1. 通过doWork()public(getter)方法,明确protected方法在行为方面的意义 ToBeTest类,或与public个对象关联的任何对象的protectedToBeTest方法。看一下Java库提供的Javadoc:它描述了所有这些类在没有声明方法体的情况下所做的事情。你的方法何时返回true?什么时候返回false?它有什么副作用?您可能会发现需要添加一些getter方法来执行此操作。你可以express these in the Javadoc for your own code
  2. 使用所需的行为来确定您可以在单元测试中放置哪种断言。