模拟 class 嵌套在 classes 中用于测试
Mock out class nested inside classes for testing
Alpha - parent beta 为 child
public class Alpha {
Beta beta;
public Alpha(int argument) {}
void start() {
beta = createBeta();
}
Beta createBeta() {
return new Beta(this);
}
}
Beta - child of alpha,有 charlie
public class Beta {
Alpha alpha;
Charlie charlie;
public Beta(Alpha alpha) {
this.alpha = alpha;
this.charlie = createCharlie();
}
Charlie createCharlie() {
return new Charlie().shuffle();
}
}
Charlie - 有一个列表,通常在生产中被洗牌
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。不确定最好的方法是什么?这是复制的确切代码。也可以更改设置以方便测试。尝试了不同的变体,但没有任何效果。非常感谢对此的帮助。
我不确定,我试了很多方法(mocking out createCharlie()
function,mocking out Charlie
class,mocking out shuffle()
,移动createCharlie()
到 parent Alpha
class,没有真正正常工作,或者我可能遗漏了一些东西。非常感谢任何帮助。谢谢!
想知道为什么我不能这样做:
Charlie charlie = Mockito.mock(Charlie.class);
Mockito.when(charlie.shuffle()).thenReturn(special);
如果有人觉得有用,我会在下面留下我的初步答案。
首先,在构造函数的最后一行 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
被称为,而不是模拟的。您实现 classes 的方式并不是很好,但如果我只是回答您应该在测试中更改的内容 - 您应该改为这样称呼:
Assert.assertEquals(special.list, alpha.beta.createCharlie().list);
在那种情况下,mocked Charlie
将被调用并且测试将通过。
上一个回答:
通常当你对某些东西进行单元测试时,你的重点是单个测试 class。您可以使用 @Spy
/@InjectMocks
。当你将测试Beta
时,你应该模拟Charlie
,当你将测试Alpha
时,你将模拟Beta
...
我不知道目的,但您的代码中的奇怪之处在于 createCharlie()
和 randomize()
returns 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();
}
}
你可以像这样在你的测试中注入 charlie:
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 文档。
您可以选择将包 protected/public 方法添加到 Alpha
:
Beta createBeta() {
return new Beta();
}
或
Beta getBeta() {
if(beta==null){
beta = new Beta();
}
return beta;
}
然后你可以注入 Alpha
真实的 Beta
,returns 模拟 Charlie
:
public class AlphaTest {
@嘲笑
查理查理莫克;
@Spy
Beta beta;
@Spy
Alpha alpha;
public void beforeTest() {
when(alpha.getBeta()).thenReturn(beta);
when(beta.getCharlie()).thenReturn(charlie);
}
}
另见 this。
感谢 Dario 的回答,我将 Beta class 更改为
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 访问 charlie,而是始终使用 getCharlie(),这应该可以解决我的问题。谢谢达里奥,非常感谢!
Alpha - parent beta 为 child
public class Alpha {
Beta beta;
public Alpha(int argument) {}
void start() {
beta = createBeta();
}
Beta createBeta() {
return new Beta(this);
}
}
Beta - child of alpha,有 charlie
public class Beta {
Alpha alpha;
Charlie charlie;
public Beta(Alpha alpha) {
this.alpha = alpha;
this.charlie = createCharlie();
}
Charlie createCharlie() {
return new Charlie().shuffle();
}
}
Charlie - 有一个列表,通常在生产中被洗牌
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。不确定最好的方法是什么?这是复制的确切代码。也可以更改设置以方便测试。尝试了不同的变体,但没有任何效果。非常感谢对此的帮助。
我不确定,我试了很多方法(mocking out createCharlie()
function,mocking out Charlie
class,mocking out shuffle()
,移动createCharlie()
到 parent Alpha
class,没有真正正常工作,或者我可能遗漏了一些东西。非常感谢任何帮助。谢谢!
想知道为什么我不能这样做:
Charlie charlie = Mockito.mock(Charlie.class);
Mockito.when(charlie.shuffle()).thenReturn(special);
如果有人觉得有用,我会在下面留下我的初步答案。
首先,在构造函数的最后一行 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
被称为,而不是模拟的。您实现 classes 的方式并不是很好,但如果我只是回答您应该在测试中更改的内容 - 您应该改为这样称呼:
Assert.assertEquals(special.list, alpha.beta.createCharlie().list);
在那种情况下,mocked Charlie
将被调用并且测试将通过。
上一个回答:
通常当你对某些东西进行单元测试时,你的重点是单个测试 class。您可以使用 @Spy
/@InjectMocks
。当你将测试Beta
时,你应该模拟Charlie
,当你将测试Alpha
时,你将模拟Beta
...
我不知道目的,但您的代码中的奇怪之处在于 createCharlie()
和 randomize()
returns 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();
}
}
你可以像这样在你的测试中注入 charlie:
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 文档。
您可以选择将包 protected/public 方法添加到 Alpha
:
Beta createBeta() {
return new Beta();
}
或
Beta getBeta() {
if(beta==null){
beta = new Beta();
}
return beta;
}
然后你可以注入 Alpha
真实的 Beta
,returns 模拟 Charlie
:
public class AlphaTest { @嘲笑 查理查理莫克;
@Spy
Beta beta;
@Spy
Alpha alpha;
public void beforeTest() {
when(alpha.getBeta()).thenReturn(beta);
when(beta.getCharlie()).thenReturn(charlie);
}
}
另见 this。
感谢 Dario 的回答,我将 Beta class 更改为
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 访问 charlie,而是始终使用 getCharlie(),这应该可以解决我的问题。谢谢达里奥,非常感谢!