如何模拟Phone对象的对象。
代码吼叫,public class Fortest {
UserDao userdao = new UserDao();
Phone name = new Phone();
public String handleUser(User user) {
String returncode="failed";
//User usr = new User("bob");
String username=user.getUsername();
String pass=user.getPass();
System.out.println("username and password : "+username+" : "+pass);
Phone name = new Phone();
String ph = name.getA();
System.out.println("ph "+ph);
if(ph.equalsIgnoreCase("test")){
System.out.println("A "+ph);
returncode="done";
}
System.out.println("returning "+returncode);
return returncode;
//System.out.println("name "+name.toString());
//System.out.println(name.getA());
}
}
由于
答案 0 :(得分:2)
你没有。模拟的一个规则是:你永远不会模拟实体或值对象。如果您需要违反此规则,则意味着您可能存在设计缺陷。
如果您需要模拟new
,则需要将工厂传递给对象,然后模拟工厂。一个非常常见的例子是当你需要模拟Date对象时,这个问题在另一个问题中得到了很好的解释:How to mock the default constructor of the Date class(查看第一个答案)。
作为附注,调用电话name
... mmm的实例看起来不正确。
答案 1 :(得分:2)
首先,我要做一些假设。
user.getUsername()
& user.getPass()
没有副作用。
System.out.println
对您来说并不重要。
这样你的课就变成了:
public class Fortest {
Phone name = new Phone();
public String handleUser(User user) {
String ph = name.getA();
if(ph.equalsIgnoreCase("test")){
return "done";
}
return "failed";
}
}
所以你的测试有两个条件。 phone.getA()
是“测试”并且您返回“已完成”或者不是,并且您返回“失败”。
那么如何设置“getA
”。有一件事是肯定的,我们需要能够从测试中设置“名称”。为此,我们需要“注入”它(我们可以通过其他方式做到,但我喜欢注射)。我会使用Guice,很多人会使用Spring。有些人会使用其他注入框架之一。但在测试中,我们大多数人都会使用手动注射。
public class Fortest {
Phone name;
Fortest(Phone name) {
this.name = name;
}
public String handleUser(User user) {
String ph = name.getA();
if(ph.equalsIgnoreCase("test")){
return "done";
}
return "failed";
}
}
public class TestFortest {
@Before
public void before() {
name = ; //...
subject = new Fortest(name);
}
}
现在测试相当简单:
public void whenTestModeIsEnabledThenReturnDone() {
setPhoneIntoTestMode();
String actual = subject.handleUser(null);
assertEquals(actual, "done");
}
public void whenTestModeIsDisabledThenReturnFailed() {
setPhoneIntoLiveMode();
String actual = subject.handleUser(null);
assertEquals(actual, "failed");
}
setPhoneIntoTestMode
/ setPhoneIntoLiveMode
的实施将取决于Phone
的复杂程度。如果它比我们想要以某种方式“嘲弄”它(嘲笑,存根等)那么复杂。这可能是你编写的一大块代码,它可能是使用像Mocketo这样的工具。
如果Phone对象很简单,并且拥有或可以使用“setA
”方法,那么就使用它。
我相信以后你需要userdao
。那时将完成同样的事情。注入并模拟/设置对象。
答案 2 :(得分:0)
使用EasyMock非常容易进行类模拟。它在内部使用cglib来执行类模拟。 EasyMock可以模拟接口和类(类模拟)。请参阅documentation。
因此,要使您的手机模拟,只需调用createMock(Phone.class):
Phone phoneMock = createMock(Phone.class);
正如奥古斯托所说,尽管如此,使用课堂模拟并不是一个好的设计。更好的方法是编程接口并使用依赖注入框架。
答案 3 :(得分:0)
因此,您需要执行以下选项之一,将模拟注入字段name
和userdao
(我将假设您可以使用new Phone
字段实例而不是在方法中创建的那个。
不要直接在代码中调用构造函数,而是通过setter使用字段注入。这将允许您的测试提供两个类的模拟实例。如果必须在方法中创建新实例,请考虑使用可以模拟的工厂。
为这两个字段提供默认范围设置方法。这些方法仅用于测试目的。
使用Refection将字段设置为模拟实例。一个简单的方法是使用Spring的ReflectionTestUtils。
一旦其中一个到位,您就可以提供模拟实例(可能使用Mockito)来驱动您想要测试的行为。我建议选项1是最好的,如果是可行的,那么选项3.但是,选项3的缺点是测试依赖于私有字段的名称。
则...
Phone phone = Mockito.mock(Phone.class);
Mockito.when(phone.getA()).thenReturn("blah");
objectUnderTest.setPhone(phone);
objectUnderTest.handleUser(...);