Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.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#_.net_Unit Testing_State - Fatal编程技术网

C# 单元测试跟踪状态的类

C# 单元测试跟踪状态的类,c#,.net,unit-testing,state,C#,.net,Unit Testing,State,我正在抽象我的一个类的历史跟踪部分,因此它看起来像这样: private readonly Stack<MyObject> _pastHistory = new Stack<MyObject>(); internal virtual Boolean IsAnyHistory { get { return _pastHistory.Any(); } } internal virtual void AddObjectToHistory(MyObject myObject)

我正在抽象我的一个类的历史跟踪部分,因此它看起来像这样:

private readonly Stack<MyObject> _pastHistory = new Stack<MyObject>();

internal virtual Boolean IsAnyHistory { get { return _pastHistory.Any(); } }

internal virtual void AddObjectToHistory(MyObject myObject)
{
  if (myObject == null) throw new ArgumentNullException("myObject");
  _pastHistory.Push(myObject);
}

internal virtual MyObject RemoveLastObject()
{
  if(!IsAnyHistory) throw new InvalidOperationException("There is no previous history.");
  return _pastHistory.Pop();
}
private readonly堆栈_pastHistory=new Stack();
内部虚拟布尔值IsAnyHistory{get{return _pastHistory.Any();}
内部虚拟void AddObjectToHistory(MyObject MyObject)
{
如果(myObject==null)抛出新的ArgumentNullException(“myObject”);
_过去的历史。推(myObject);
}
内部虚拟MyObject RemovelAsObject()
{
如果(!IsAnyHistory)抛出新的InvalidOperationException(“没有以前的历史记录”);
return_pastHistory.Pop();
}
我的问题是,我想单元测试Remove将返回最后添加的对象

  • AddObjectToHistory
  • RemoveObjectToHistory
    ->返回通过
    AddObjectToHistory

然而,如果我必须先调用Add,那么这不是真正的单元测试?但是,我能看到的以真正的单元测试方式实现这一点的唯一方法是在构造函数中传递堆栈对象或模拟
IsAnyHistory
…但是模拟我的SUT也是很奇怪的。所以,我的问题是,从教条的观点来看,这是一个单元测试吗?如果没有,我该如何清理它…这是我唯一的方法吗?在一个简单的物体中,这看起来像是一个拉伸?把这个简单的对象推出来注射可以吗?

我认为这仍然是一个单元测试,假设MyObject是一个简单的对象。我经常构造单元测试方法的输入参数

我使用:

在以下情况下,测试不是单元测试:

  • 它与数据库通信
  • 它通过网络进行通信
  • 它涉及到文件系统
  • 它不能与任何其他单元测试同时运行
  • 您必须对您的环境执行特殊操作(例如编辑配置文件)才能运行它
做这些事情的测试并不坏。通常,它们值得编写,并且可以在单元测试工具中编写。然而,能够将它们与真正的单元测试分开是很重要的,这样我们就可以保留一组测试,以便在进行更改时能够快速运行


我认为您试图对单元测试的定义过于具体。您应该测试类的公共行为,而不是具体的实现细节


从代码片段来看,您真正需要关心的是a)调用AddObjectToHistory是否会导致IsAnyHistory返回true,b)RemovelAsObject是否最终会导致IsAnyHistory返回false

对于这些场景,有两种方法:

  • 干扰设计,如使
    \u过去历史
    内部
    /
    受保护
    或注入堆栈
  • 使用其他(可能是单元测试)方法进行验证
  • 和往常一样,没有黄金法则,尽管我想说您通常应该避免单元测试强制设计更改的情况(因为这些更改很可能会给代码使用者带来歧义/不必要的问题)

    尽管如此,最终还是要由您来权衡您希望单元测试代码在多大程度上干扰设计(第一种情况)或扭曲完美的单元测试定义(第二种情况)


    通常,我觉得第二种情况更吸引人——它不会扰乱原始类代码,而且您很可能已经测试了
    Add

    如其他答案中所述,我认为您的选项可以这样分解

  • 您对您的测试方法采取教条式的方法,并为堆栈对象添加构造函数注入,以便可以注入您自己的伪堆栈对象并测试您的方法

  • >P>编写一个单独的添加和移除测试,删除测试将使用Add方法,但将其视为测试设置的一部分。只要您的add测试通过,您的remove也应该通过


    我的2美分。。。客户如何知道删除是否有效?“客户机”应该如何与该对象交互?客户端是否要将堆栈推送到历史跟踪器?将测试视为测试对象的另一个用户/消费者/客户。。使用与实际生产中完全相同的交互。 我还没有听说过任何规则规定不允许对测试对象调用多个方法

    要进行模拟,堆栈不是空的。我会打电话给99%的客户。我不会破坏那个物体的封装。。像对待人一样对待对象(我想我在对象思考中读到了这一点)。告诉他们做点什么。。不要闯进来

    e、 如果你想让某人钱包里有一些钱

    • 简单的方法是给他们钱,让他们自己把钱放进钱包里
    • 扔掉他们的钱包,塞进他们口袋里的钱包
    我喜欢选项1。还要看看它是如何使您从实现细节中解脱出来的(这些细节会导致测试的脆弱性)。比如说,明天这个人决定使用在线钱包。后一种方法将破坏您的测试-它们需要更新,以便立即推入在线钱包-即使对象行为没有破坏

    我看到的另一个例子是测试Repository.GetX(),在这个例子中,人们闯入数据库,在单元测试中使用SQL注入记录。。在这里,首先调用Repository.AddX(x)会更干净、更容易。孤立是可取的,但其程度不能超过实用主义


    我希望我在这里没有表现得太强。。看到对象API被“为了可测试性而扭曲”到不再像“可以工作的最简单的事情”的地步,我感到很痛苦

    Hrmmm,但我的问题是,为了测试我的实际工作单元,我必须依赖其他工作单元(
    AddObjectToHistory
    )。所以,我觉得这更像是一个单元测试。如果add-ever发生变化,那么我的remove测试将失败,因此它会使测试对另一个单元变得脆弱…我可以看到双方真的…jus