junit测试类,用于以下代码

如何模拟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()); } } 

谢谢

首先,我要做一些假设。 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()是“测试”而你返回“完成”或者它不是,你返回“失败”。

那么如何设置set“ 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 。 那时将完成同样的事情。 注入并模拟/设置对象。

你没有。 模拟的一个规则是:你永远不会模拟实体或值对象。 如果您需要违反此规则,则意味着您可能存在设计缺陷。

如果你需要模拟一个new ,你需要将一个工厂传递给该对象,然后你嘲笑工厂。 一个非常常见的例子是当你需要模拟Date对象时,这在另一个问题中得到了很好的解释: 如何模拟Date类的默认构造函数 (检查第一个答案)。

作为附注,调用电话name … mmm的实例看起来不正确。

使用EasyMock很容易进行类模拟 。 它在内部使用cglib来执行类模拟。 EasyMock可以模拟接口类(类模拟)。 见文档 。

因此,要使您的手机模拟,只需调用createMock(Phone.class):

 Phone phoneMock = createMock(Phone.class); 

正如奥古斯托所说,尽管如此,使用类模拟并不是一个好的设计。 更好的方法是编程接口并使用dependency injection框架。

因此,您需要执行以下选项之一,将mocks注入字段nameuserdao (我假设您可以使用new Phone字段实例而不是方法中创建的实例。

  1. 不要直接在代码中调用构造函数,而是通过setter使用字段注入。 这将允许您的测试提供两个类的模拟实例。 如果必须在方法中创建新实例,请考虑使用可以模拟的工厂。

  2. 为这两个字段提供默认范围设置方法。 这些方法仅用于测试目的。

  3. 使用Refection将字段设置为模拟实例。 一个简单的方法是使用Spring的ReflectionTestUtils。

一旦其中一个到位,您可以提供模拟实例(可能使用Mockito)来驱动您希望测试的行为。 我建议选项1是最好的,如果是可行的,那么选项3.但是,选项3的缺点是测试依赖于私有字段的名称。

然后…

 Phone phone = Mockito.mock(Phone.class); Mockito.when(phone.getA()).thenReturn("blah"); objectUnderTest.setPhone(phone); objectUnderTest.handleUser(...);