例如,我有一个java类,如下所示。我将为doWork()编写一个单元测试,所以我想控制obj的行为。但很明显,obj是在内部实例化的。
我怎么写这个UT?现在我正在使用Junit + Mockito。
class ToBeTest{
public ToBeTest(){}
public boolean doWork(){
OtherObject obj=new OtherObject();
return obj.work();
}
}
提前致谢。 :)
BTW,现实是我正在为其他人的班级写UT。所以我不想改变它。它已通过集成测试进行了全面测试。
答案 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)
您已编写代码,现在您想对其进行单元测试。这是你遇到困难的根本原因。我建议采用不同的方法。
doWork()
和public
(getter)方法,明确protected
方法在行为方面的意义仅 ToBeTest
类,或与public
个对象关联的任何对象的protected
和ToBeTest
方法。看一下Java库提供的Javadoc:它描述了所有这些类在没有声明方法体的情况下所做的事情。你的方法何时返回true
?什么时候返回false
?它有什么副作用?您可能会发现需要添加一些getter方法来执行此操作。你可以express these in the Javadoc for your own code。