代码之家  ›  专栏  ›  技术社区  ›  Leonardo

如何对以下场景进行单元测试?

  •  0
  • Leonardo  · 技术社区  · 5 年前

    我有以下方法

        public override void SendSync(int frame, byte[] syncData)
        {
            using (var ms = new MemoryStream(4 + syncData.Length))
            {
                ms.WriteArray(BitConverter.GetBytes(frame));
                ms.WriteArray(syncData);
    
                queuedSyncPackets.Add(ms.GetBuffer());
            }
        }
    

    我想对它进行单元测试,以保证两件事:

    1. 这个 ms 位于末端 ok将使用roslyn
    2. 4 + syncData.Length 等于 ms.GetBuffer().Capacity 就在 queuedSyncPackets.Add(ms.GetBuffer());

    我该怎么做?

    0 回复  |  直到 5 年前
        1
  •  0
  •   Alexei Levenkov    5 年前

    哲学部分:

    你们真的不应该对方法内部的实现方式进行单元测试。您应该测试它的行为是否正确,但不应该要求特定的实现。在这种情况下,只使用新数组和两个复制操作来实现方法而不是使用MemoryStream会更清楚——要求方法创建和处理内存流或使用特定的字节数组可能是错误的。事实上,如果你希望使用一些特定的缓存/池,你可以断言这一点。

    ms被置于末尾:

    测试是否存在 using 在 MemoryStream 用法-因为 内存流 没有非托管组件,如果你有一个或没有非托管的组件,并且显示了代码,那么绝对不会有任何变化( Dispose 将阻止未来可能影响其他使用模式的读/写操作)。因此,这种特殊情况在很大程度上是风格偏好,应该被代码分析器或代码审查所发现。

    如果你真的想测试这一点,一个选择是将流的创建移动到工厂方法中,并捕获创建的流以供以后验证。类似的东西

     public override void SendSync(
           int frame, byte[] syncData, Func<MemoryStream> streamFactory)
     {
           using (var ms = streamFactory())...
     }
    
     ...MyTest()
     {
        var ms = new MemoryStream();
        SendSync(..., ()=>ms);
        Assert.IsFalse(ms.CanRead, 
           "Expecting stream to be disposed and hence no more readable");
     }
    

    注意:正如评论和问题中提到的,对于这个特定案例来说,测试流是否已被处理可能有点过头了。如果有人认为没有必要将其删除,而其他人则将其添加回“我们的编码标准要求”,这无法通过单元测试来解决——请与人交谈。

    检查方法的参数:

    假设 queuedSyncPackets 是一种注入的依赖关系,您只需在调用时添加对预期数据的检查。通常使用一些模拟框架完成,如 moq ,但您可以实现自己的类,该类只是检查该调用中的数组大小。

    请注意,文章中显示的代码将成功通过检查,但并非必须如此(因为这部分行为没有记录在案)。 GetBuffer() 退货 内部阵列 MemoryStream的大小和结果数据相同或更大,但不能保证在没有剩余空间时不会增长流。如果你必须使用 GetBuffer() 你也必须通过溪流的大小。

    使用moq进行测试的近似样本:

    byte[] theBuffer = null;
    mockQueuedSyncPackets.Setup(c => c.Add(It.IsAny<byte[]>()))
            .Callback<byte[]>((obj) => theBuffer = obj);
    var theSender = new Sender(mockQueuedSyncPackets.Object);
    theSender.SendSync(123, syncData);
    Assert.AreEqual(4 + syncData.Length, theBuffer.Length);