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



Alpha - 以 beta 为子级的父级

public class Alpha {
  Beta beta;
  public Alpha(int argument) {}
  void start() {
    beta = createBeta();
  }
  Beta createBeta() {
    return new Beta(this);
  }
}

贝塔 - 阿尔法的孩子,有查理

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);
  }
}

目标是用查理的不同组合来测试Alpha/Beta。不确定最好的方法是什么?这是复制的确切代码。也愿意更改设置以方便测试。尝试了不同的变体,没有什么真正起作用的。非常感谢对此的帮助。

不确定,我尝试了很多方法(模拟createCharlie()功能,模拟Charlie类,模拟shuffle()createCharlie()移动到父类Alpha,没有什么真正正常工作,或者我错过了一些东西。任何帮助将不胜感激。谢谢!

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

Charlie charlie = Mockito.mock(Charlie.class);
Mockito.when(charlie.shuffle()).thenReturn(special);

如果有人觉得这有用,我会在下面留下我的初步答案。

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

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

运行测试后,您将看到查理被多次创建。

首先,当在测试中调用它时:

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的实例。无论如何,你可以通过getter懒惰地创建Charlie,如下所示:

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();
    }
}

另请参阅@InjectMocks文档。

(可选(您可以将包保护/公共方法添加到Alpha

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

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

然后你可以注入Alpha真实的Beta返回模拟Charlie

公共类 AlphaTest { @Mock 查理查理莫克;

@Spy
Beta beta;
@Spy
Alpha alpha;
public void beforeTest() {
    when(alpha.getBeta()).thenReturn(beta);
    when(beta.getCharlie()).thenReturn(charlie);
}

}

另请参阅此内容。

感谢达里奥的回答,我将 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((,这应该可以解决我的问题。谢谢达里奥,非常感谢!

相关内容

  • 没有找到相关文章