Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用假货';在同一对象中的另一个方法上调用_C#_Unit Testing_Fakeiteasy - Fatal编程技术网

C# 使用假货';在同一对象中的另一个方法上调用

C# 使用假货';在同一对象中的另一个方法上调用,c#,unit-testing,fakeiteasy,C#,Unit Testing,Fakeiteasy,使用FakeiTasy,我如何检查我的对象的方法是否调用了同一对象上的另一个方法 测试: [TestMethod] public void EatBanana_CallsWillEat() { var banana = new Banana(); var myMonkey = new Monkey(); myMonkey.EatBanana(banana); //this throws an ArgumentException, because myMonkey is a r

使用FakeiTasy,我如何检查我的对象的方法是否调用了同一对象上的另一个方法

测试:

[TestMethod]
public void EatBanana_CallsWillEat()
{
  var banana = new Banana();
  var myMonkey = new Monkey();

  myMonkey.EatBanana(banana);

  //this throws an ArgumentException, because myMonkey is a real instance, not a fake
  A.CallTo(() => myMonkey.WillEat(banana)
    .MustHaveHappened();
}
班级:

public class MyMonkey {
  private readonly IMonkeyRepo _monkeyRepo;

  public MyMonkey(IMonkeyRepo monkeyRepo) {
    _monkeyRepo = monkeyRepo;
  }

  public void EatBanana(Banana banana) {
    //make sure the monkey will eat the banana
    if (!this.WillEat(banana)) {
      return;
    }

    //do things here
  }

  public bool WillEat(Banana banana) {
    return !banana.IsRotten;
  }
}
我愿意接受建议。如果我在这件事上做错了,请告诉我。

这样做是可能的。如果
将eat
方法是虚拟的,否则FakeiTesy将无法伪造它

通过这一更改,您可以执行以下操作:

[TestMethod]
public void EatBanana_CallsWillEat()
{
    var fakeMonkey = A.Fake<MyMonkey>();

    fakeMonkey.EatBanana(new Banana());

    A.CallTo(()=>fakeMonkey.WillEat(A<Banana>._)).MustHaveHappened();
}
[TestMethod]
公共电话号码()
{
var fakeMonkey=A.Fake();
fakeMonkey.eatbana(新香蕉());
A.CallTo(()=>fakeMonkey.WillEat(A.);
}

我仍然不相信这是一个好主意(正如我在评论中咆哮的那样)——我认为你最好依靠其他可观察到的行为,但我不熟悉你的系统。如果您认为这是最好的方法,那么示例代码应该适合您。

为什么要模拟测试对象?你到底想测试什么?对
的调用将执行
的验证没有什么价值。it向消费者提供哪些信息?毕竟,消费者并不关心方法是如何实现的。消费者关心结果是什么

当猴子吃了香蕉而香蕉并没有腐烂时会发生什么?您的测试应回答以下问题:

[TestMethod]
public void EatBanana_CAUSES_WHAT_WhenBananaIsNotRotten()
{
    var repo = A.Fake<IMonkeyRepo>();
    var monkey = new Monkey(repo);
    var freshBanana = new Banana { IsRotten = false };

    monkey.EatBanana(freshBanana);

    // verifications here depend on what you expect from
    // monkey eating fresh banana
}
[TestMethod]
公共利益导致了什么
{
var repo=A.Fake();
风险值猴子=新猴子(回购);
var freshBanana=newbanana{IsRotten=false};
猴子。吃香蕉(新鲜香蕉);
//这里的验证取决于您期望从中得到什么
//猴子吃新鲜香蕉
}

请注意,您可以对
IMonkeyRepo
进行各种验证,这是正确伪造并在此处注入的。

据我所知,这并不是FIE的真正目的。FIE提供了假对象,因此您的生产代码可以更容易地戳和戳。正如你所指出的,你没有假的。根据我的经验,这种测试通常不是一个好主意。您的MyMonkey类应该是一个相当独立的单元,您最好在被命令吃香蕉时测试它的整体行为,而不是担心它是否调用了自己的方法。例如,你能根据“/”中发生的事情判断香蕉是否被吃掉吗?@BlairConrad在我的真实场景中,WillEat更复杂,有自己的测试,这只是EatBanana的测试之一。在这个测试中,如果我让EatBanana调用真正的WillEat,我不是在一个测试中测试两个特性吗?然后,如果WillEat改变,它可能会打破这个测试,这是个坏消息,对吗?我明白你的意思。这很棘手。如果
要吃另一个对象,我们都会敦促伪造该对象并将其注入
MyMonkey
(听起来很痛苦)。我真正能说的是,我认为最好的默认位置是尝试从外部测试
MyMonkey
,依靠客户的可观察结果。但是,您已经考虑过了,并且已经找到了一个解决方案,它将节省您的痛苦,减少测试的数量以及在给定时间内中断的数量。你最了解代码,所以如果它对你有用的话……我只是想让你知道另一种选择。很好。如果我不模仿WillEat,并且允许EatBanana调用真正的WillEat,那么我是否在一个测试中测试了两个特性?在本例中,WillEat很简单,但在我的实际情况中,它更复杂,并且根据它的参数返回一个派生对象,因此我认为模拟它并验证它是否被调用是正确的方法。目前,我对WillEat进行了单独的测试,对EatBanana进行了一些其他测试,包括验证是否调用了回购协议。也许我变得太细了?@JoshNoe:也许你变得不够细了。如果
会吃
那么复杂,也许它应该生活在自己的类中?也许将这一特性提取到食物评估器之类的东西中,并将其注射到猴子身上更有意义?测试应该是简单的——如果不是,通常是一个很好的指标,表明设计可以重新进行。另一方面,为什么
Monkey
依赖于
IMonkeyRepository