junit测试类,用于以下代码

时间:2012-09-05 09:43:51

标签: java 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());
  }
}

由于

4 个答案:

答案 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)

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

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

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

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

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

    则...

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