模拟出嵌套在类中的类进行测试

时间:2016-04-14 05:36:46

标签: java unit-testing testing mocking mockito

Alpha - 以beta为孩子的父母

public class Alpha {
  Beta beta;

  public Alpha(int argument) {}

  void start() {
    beta = createBeta();
  }

  Beta createBeta() {
    return new Beta(this);
  }
}

Beta - alpha的孩子,有查理

public class Beta {
  Alpha alpha;
  Charlie charlie;

  public Beta(Alpha alpha) {
    this.alpha = alpha;
    this.charlie = createCharlie();
  }

  Charlie createCharlie() {
    return new Charlie().shuffle();
  }
}

查理 - 有一个清单,通常在生产中洗牌

public class Charlie {
  List<Integer> list = new ArrayList<Integer>();

  public Charlie() {
    for (int i = 0; i < 6; i++) {
      list.add(i);
    }
  }

  public Charlie shuffle() {
    Collections.shuffle(list);
    return this;
  }

  @Override
  public String toString() {
    return list.toString();
  }
}

AlphaTest [需要帮助进行此测试] - 想尝试不同的改组变体,看看alpha / beta会如何反应。

public class AlphaTest {

  Charlie special = new Charlie();

  @Test
  public void testSpecialCharlie() {
    Alpha alpha = Mockito.spy(new Alpha(0));
    Beta beta = Mockito.spy(alpha.createBeta());

    Mockito.when(alpha.createBeta()).thenReturn(beta);
    Mockito.when(beta.createCharlie()).thenReturn(special);

    alpha.start();

    // FAILURE: expected:<[0, 1, 2, 3, 4, 5]> but was:<[0, 4, 1, 5, 3, 2]>
    assertEquals(special.list, alpha.beta.charlie.list);
  }
}

目标是使用Charlie的不同组合测试Alpha / Beta。不确定最好的方法是什么?这是复制的确切代码。打开更改设置也便于测试。尝试了不同的变化,没有什么真正有效。真的很感激这方面的帮助。

我不确定,我尝试了很多方法(嘲笑createCharlie()函数,嘲笑Charlie类,嘲笑shuffle(),将createCharlie()移到父{ {1}}课程,没有什么能正常工作,或者我错过了什么。任何帮助都会非常感激。谢谢!

不知道为什么我不能这样做:

Alpha

2 个答案:

答案 0 :(得分:0)

如果有人发现这个有用的话,我会在下面留下我的初步答案。

首先,在构造函数的最后一行放入Beta

System.out.println("Charlie created: " + this.charlie.hashCode());

运行测试后,您将看到多次创建charlie。

首先在测试中调用它:

Beta beta = Mockito.spy(alpha.createBeta());

以及稍后调用它时:

Mockito.when(alpha.createBeta()).thenReturn(beta);

因此,Beta会保留对真实Charlie的引用,因为您在调用代码时嘲笑createCharlie()

Assert.assertEquals(special.list, alpha.beta.charlie.list);

调用真实Charlie,而不是模拟真实Assert.assertEquals(special.list, alpha.beta.createCharlie().list); 。你如何实现你的课程的方式并不是很好,但如果我只是回答你应该在测试中改变的内容 - 你应该这样称呼它:

Charlie

在这种情况下,将调用模拟@Spy并且测试将通过。

上一个回答:

通常,当您对某些内容进行单元测试时,您的重点是单个测试类。您可以使用@InjectMocks / Beta。当你测试Charlie时,你应该模仿Alpha,当你测试Beta时,你会模仿createCharlie() ......

我不知道目的,但代码中很奇怪randomize()Charlie会返回Charlie的实例。无论如何,你可以通过getter懒洋洋地创建public class Beta { private Charlie charlie; public Beta() { } public Charlie getCharlie() { if (charlie == null) { charlie = new Charlie(); } return charlie; } public void doSomethingWithCharlie() { getCharlie().randomize(); } } ,如下所示:

public class BetaTest{
    @Mock(name="charlie") // variable name in Beta
    private Charlie charlieMock;

    @InjectMocks
    private Beta beta;

    @BeforeMethod
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    public void test1(){
        beta.doSomethingWithCharlie();
    }
}

你可以在你的测试中注入charlie:

Alpha

另见@InjectMocks文档。

您可以选择将包受保护/公共方法添加到Beta createBeta() { return new Beta(); }

Beta getBeta() {
    if(beta==null){
        beta = new Beta();
    }

    return beta;
}

Alpha

然后你可以注入Beta真实的Charlie,它会返回模拟的@Spy Beta beta; @Spy Alpha alpha; public void beforeTest() { when(alpha.getBeta()).thenReturn(beta); when(beta.getCharlie()).thenReturn(charlie); }

公共类AlphaTest {     @嘲笑     查理查理莫克;

$ rm -f {your_web_app}/storage/framework/sessions/*

}

另见this

答案 1 :(得分:0)

感谢Dario的回答,我将Beta类更改为

public class Beta {
  Alpha alpha;
  Charlie _charlie;

  public Beta(Alpha alpha) {
    this.alpha = alpha;
    this._charlie = getCharlie();
    // PROBLEM: If I use this._charlie here, that will use the wrong charlie!
  }

  Charlie getCharlie() {
    if (_charlie == null) {
      _charlie = new Charlie().shuffle();
    }
    return _charlie;
  }
}

然后,我从未使用alpha.beta._charlie和getCharlie()访问charlie,这应该可以解决我的问题。谢谢达里奥,非常感谢!