例如,我有一个java类,如下所示。我将为doWork()编写一个单元测试,所以我想控制obj的行为。但很明显,obj是在内部实例化的。
我怎么写这个UT?现在我正在使用Junit + Mockito。
class ToBeTest{
public ToBeTest(){}
public boolean doWork(){
OtherObject obj=new OtherObject();
return obj.work();
}
}
提前致谢。 :)
顺便说一句,现实是我正在为其他人的班级写UT。所以我不想改变它。它已经过集成测试的全面测试。
如果您无法更改代码,可以使用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"));
}
最好的方法是 编写代码以支持测试 (测试驱动开发 正在强调这一点)。目前,您的代码以难以测试的方式编写。
请 考虑使用依赖注入,因为它可以帮助你模拟依赖对象。
你不能轻易。我可以想到两种方法可以做到这一点,据我所知,Mockito或jUnit都不支持开箱即用:
1)使用cglib或类似库的字节代码操作,这将是适度难以做到的并且可能非常脆弱。
2)备用类加载器。您可以构建一个类加载器,该类加载器查找尝试加载OtherObject类并将其替换为匿名的OtherObject类,该类提供您正在查找的模拟行为。
大多数情况下,你应该将它视为依赖。如果你想测试打开一个文件,你可能真的想用文件测试,所以使用具体的类可能没问题。如果你想测试一个方法的行为,即打开一个文件作为它逻辑的一部分,你可以轻松地将它移到一个依赖项然后模拟它。事实上,这通常是有道理的,因为你有一天存储在文件中的内容,可能需要存储在另一个数据库中,或者在第三天从云中下载,因此将逻辑与你对文件的处理分开无论如何,打开检索内容的实际过程通常是关注的逻辑分离。
这是您应该使用的经典示例 依赖注入。
简而言之,不是在内部创建对象(依赖),而是在构造函数中传递它或使用工厂来创建所需的东西(工厂在生产代码中返回实际实现,在测试中返回另一个)。这使您可以在测试时更改实现。
看看我提供的类似的例子或google for“Java依赖注入示例”。
这很容易:
import org.junit.*;
import mockit.*;
@Test
public void justMockIt()
{
new NonStrictExpectations() { OtherObject o; { o.work(); result = true; }};
assert new ToBeTest().doWork();
}
......使用时 JMockit。
你已经编写了代码,现在你想对它进行单元测试。这是你遇到困难的根本原因。我建议采用不同的方法。
- 表达了什么
doWork()
方法意味着在可以观察到的行为方面做 只要 通过 public
和 protected
(getter)方法 ToBeTest
上课,或者 public
和 protected
任何与之关联的对象的方法 ToBeTest
对象。看一下Java库提供的Javadoc:它描述了所有这些类的功能 无 陈述方法的主体。你的方法何时返回 true
?什么时候回来 false
?它有什么副作用?您可能会发现需要添加一些getter方法来执行此操作。你可以 在Javadoc中为您自己的代码表达这些。
- 使用所需的行为来确定可以在单元测试中放置哪种断言。