Java 嵌套在类中用于测试的模拟类

Java 嵌套在类中用于测试的模拟类,java,unit-testing,testing,mocking,mockito,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); } } 贝塔-阿尔法的孩子,查理 public class Beta { Alpha alpha; Charlie char

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

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

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

System.out.println("Charlie created: " + this.charlie.hashCode());
运行测试后,您将看到charlie被创建了多次

首先,在测试中调用时:

Beta beta = Mockito.spy(alpha.createBeta());
后来,当这被称为:

Mockito.when(alpha.createBeta()).thenReturn(beta);
因此,Beta版保留了对real
Charlie
的引用,并且因为您在调用代码时模拟了
createCharlie()

Assert.assertEquals(special.list, alpha.beta.charlie.list);
真正的
Charlie
被调用,而不是模拟的。您实现类的方式并不是很好,但如果我只回答您在测试中应该更改的内容,您应该称之为:

Assert.assertEquals(special.list, alpha.beta.createCharlie().list);
在这种情况下,将调用mocked
Charlie
,测试将通过


先前的答复:

通常,当您进行单元测试时,您的注意力集中在单个测试类上。您可以使用
@Spy
/
@injectmock
。当你测试
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();
    }
}
您可以像这样在测试中注入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();
    }
}
另见文件

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

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

然后你可以注入
Alpha
real
Beta
,返回mocked
Charlie

公开课字母测验{ @嘲弄 查理·查理·莫克

@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。_charlie并且总是使用getCharlie(),这应该可以解决我的问题。谢谢你,达里奥,非常感谢

“什么都不能正常工作”是什么意思?对不起,我的意思是,我无法让它正常工作,我对测试非常陌生,所以我可能做得不对。我也可以稍微调整一下设置。请告诉我你会怎么做?谢谢使用JMockit对这样的代码进行单元测试非常容易(您只需声明一个
@Mocked Beta
@Mocked Charlie
字段/参数,然后记录/验证任何调用,而不管实例是如何在CUT中创建的)。。。然而,我想问,为什么首先要嘲笑这里的一切?记住,嘲笑是不能滥用的。像Kent Beck(TDD的创始人)、Martin Fowler和其他“大师”这样的人不喜欢嘲弄(有充分的理由)。实际上我不知道什么是最好的方式。我没有设置JMockit。我认为这应该很简单,测试经验有限,但已经浪费了几天时间,仍然无法解决:(感谢Dario,也许我不清楚,我在问题中添加了更多信息。我同意测试单个类,但不幸的是,在这种情况下,Beta依赖于Alpha,我无法将它们解耦。目标是验证Alpha/Beta与不同charlie的交互,这就是为什么我想模拟charlie的创建,以便我可以再次编写测试st个不同的Charlie实例。希望能澄清一点?我还在回复中添加了其他信息。我尝试了第二种方法,但没有成功:(-我不确定我遗漏了什么,这也是我以前尝试过的。使用debug并验证Mock是否已注入Hi Dario,请再看一看问题。这是复制的精确代码,因此您确切知道我正在尝试做什么。非常感谢您为此花时间。非常期待您的下一次答复。添加了注释abo我真正需要的是设置我的代码,以便第一个getCharlie()调用返回
特殊的
实例。
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;
  }
}