首页 > 解决方案 > 单元测试基类和派生类

问题描述

所以我有2节课。ItemWithAttributesItemWithNameAndAttributes(从 1 派生)。

using System;
using System.Collections.Generic;
using System.Linq;
using Helpers;

namespace Objects.Base
{
    public class ItemWithAttributes
    {
        public IEnumerable<string> Attributes { get; }

        public ItemWithAttributes(IEnumerable<string> attributes)
        {
            if (attributes == null)
                throw new ArgumentNullException(nameof(attributes), "Parameter can not be mull.");

            Attributes = attributes.ToArray();
        }

        public virtual string AttributesToParenthesesString(bool prependSpace)
        {
            return $"{Attributes.ToParenthesesString(prependSpace)}";
        }

        public override string ToString()
        {
            return AttributesToParenthesesString(false);
        }
    }
}
using System;
using System.Collections.Generic;

namespace Objects.Base
{
    public class ItemWithNameAndAttributes : ItemWithAttributes
    {
        public string Name { get; }

        public ItemWithNameAndAttributes(string name, IEnumerable<string> attributes) : base(attributes)
        {
            if (name == null)
                throw new ArgumentNullException(nameof(name), "Parameter can not be null.");

            if (name.Length == 0)
                throw new ArgumentException("Parameter can not be empty.", nameof(name));

            Name = name;
        }

        public override string ToString()
        {
            return $"{Name}{AttributesToParenthesesString(true)}";
        }
    }
}

我想进行单元测试,所以这就是我迄今为止为我的两个课程所做的。我对测试方法命名的命名约定做了一些阅读,但我现在感觉有点卡住了。

using System;
using System.Collections.Generic;
using System.Linq;
using Objects.Base;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests.Objects.Base
{
    [TestClass]
    public class ItemWithAttributesTests
    {
        [TestMethod]
        public void Constructor_AttributesWithElements_PropertyEqualToInput()
        {
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            CollectionAssert.AreEqual(attributes, itemWithAttributes.Attributes.ToList());
        }

        [TestMethod]
        public void Constructor_AttributesWithoutElements_PropertyEqualToInput()
        {
            var attributes = new List<string>() { };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            CollectionAssert.AreEqual(attributes, itemWithAttributes.Attributes.ToList());
        }

        [TestMethod]
        public void Constructor_AttributesNull_ThrowArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(() => new ItemWithAttributes(null));
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithElementsAndPrependFalse_ReturnsEqualString()
        {
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.AttributesToParenthesesString(false);

            Assert.AreEqual("(Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithElementsAndPrependTrue_ReturnsEqualString()
        {
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.AttributesToParenthesesString(true);

            Assert.AreEqual(" (Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithoutElementsAndPrependFalse_ReturnsEqualString()
        {
            var attributes = new List<string>() {  };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.AttributesToParenthesesString(false);

            Assert.AreEqual("", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithoutElementsAndPrependTrue_ReturnsEqualString()
        {
            var attributes = new List<string>() {  };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.AttributesToParenthesesString(true);

            Assert.AreEqual("", result);
        }

        [TestMethod]
        public void ToString_AttributesWithElements_ReturnsEqualString()
        {
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.ToString();

            Assert.AreEqual("(Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void ToString_AttributesWithoutElements_ReturnsEqualString()
        {
            var attributes = new List<string>() { };
            var itemWithAttributes = new ItemWithAttributes(attributes);

            var result = itemWithAttributes.ToString();

            Assert.AreEqual("", result);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using Objects.Base;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests.Objects.Base
{
    [TestClass]
    public class ItemWithNameAndAttributesTests
    {
        [TestMethod]
        public void Constructor_NameAndAttributesWithElements_PropertiesAreEqualToInput()
        {
            var name = "Name";
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            Assert.AreEqual(name, itemWithNameAndAttributes.Name);
            CollectionAssert.AreEqual(attributes, itemWithNameAndAttributes.Attributes.ToList());
        }

        [TestMethod]
        public void Constructor_NameAndAttributesWithoutElements_PropertiesAreEqualToInput()
        {
            var name = "Name";
            var attributes = new List<string>() { };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            Assert.AreEqual(name, itemWithNameAndAttributes.Name);
            CollectionAssert.AreEqual(attributes, itemWithNameAndAttributes.Attributes.ToList());
        }


        [TestMethod]
        public void Constructor_NameEmpty_ThrowArgumentException()
        {
            var name = string.Empty;
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            Assert.ThrowsException<ArgumentException>(() => new ItemWithNameAndAttributes(name, attributes));
        }

        [TestMethod]
        public void Constructor_NameNull_ThrowArgumentNullException()
        {
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            Assert.ThrowsException<ArgumentNullException>(() => new ItemWithNameAndAttributes(null, attributes));
        }

        [TestMethod]
        public void Constructor_AttributesNull_ThrowArgumentNullException()
        {
            var name = "Name";
            Assert.ThrowsException<ArgumentNullException>(() => new ItemWithNameAndAttributes(name, null));
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithElementsAndPrependFalse_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.AttributesToParenthesesString(false);

            Assert.AreEqual("(Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithElementsAndPrependTrue_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.AttributesToParenthesesString(true);

            Assert.AreEqual(" (Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithoutElementsAndPrependFalse_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.AttributesToParenthesesString(false);

            Assert.AreEqual("", result);
        }

        [TestMethod]
        public void AttributesToParenthesesString_AttributesWithoutElementsAndPrependTrue_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.AttributesToParenthesesString(true);

            Assert.AreEqual("", result);
        }

        [TestMethod]
        public void ToString_AttributesArgumentIsListWithElements_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.ToString();

            Assert.AreEqual("Name (Item 1) (Item 2) (Item 3) (Item 4) (Item 5)", result);
        }

        [TestMethod]
        public void ToString_AttributesArgumentIsListWithoutElements_ReturnsEqualString()
        {
            var name = "Name";
            var attributes = new List<string>() { };
            var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

            var result = itemWithNameAndAttributes.ToString();

            Assert.AreEqual("Name", result);
        }
    }
}

我注意到我的派生类的单元测试与ItemWithNameAndAttributes我的基类几乎相同,ItemWithAttributes但只是更多和不同,因为我还需要验证 name 参数。我不确定这是否是正确的方法,或者是否有某种方法可以在派生类中重用基类中的测试。如果我保持这种当前模式,当我从中派生时,ItemWithNameAndAttributes我将有更多相同的测试并重新测试基类。我觉得我的小班很快就变得非常复杂。

标签: c#unit-testing

解决方案


根据示例代码,我没有看到通过继承进行整合的好方法。测试确实遵循几乎相同的结构(实例化一个对象,对那个对象做一些事情,验证结果——即,安排,行动,断言),但实现细节是有意义的不同(“行动”步骤是相同的,但构造函数和预期结果不同)。在这种情况下,测试和断言框架已经完成了尽可能多的重复数据删除。

注意:使用一些单元测试框架(我主要使用xUnit.net),可以创建单元测试的继承层次结构,其中所有基本夹具的测试作为每个继承夹具的一部分运行,但我不认为那是有助于示例问题。是另一个描述继承测试的答案。

如果您愿意使用 xUnit 作为您的测试框架,您可以使用“理论”来整合一些测试:

public class ItemWithNameAndAttributesTests_Theories
{
    [Theory]
    [InlineData("Name", new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" })]
    [InlineData("Name", new string[0])]
    public void Verify_Constructor_PropertiesAreEqualToInput(string name, string[] attributes)
    {
        var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, new List<string>(attributes));

        Assert.Equal(name, itemWithNameAndAttributes.Name);
        Assert.Equal(attributes, itemWithNameAndAttributes.Attributes);
    }

    [Theory]
    [InlineData("", new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }, typeof(ArgumentException))]
    [InlineData(null, new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }, typeof(ArgumentNullException))]
    [InlineData("Name", null, typeof(ArgumentNullException))]
    public void Verify_Constructor_ThrowException(string name, string[] attributes, Type exceptionType)
    {
        Assert.Throws(exceptionType, () => new ItemWithNameAndAttributes(name, attributes));
    }

    [Theory]
    [InlineData("Name", new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }, false, "(Item 1) (Item 2) (Item 3) (Item 4) (Item 5)")]
    [InlineData("Name", new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }, true, " (Item 1) (Item 2) (Item 3) (Item 4) (Item 5)")]
    [InlineData("Name", new string[0], false, "")]
    [InlineData("Name", new string[0], true, "")]
    public void Verify_AttributesToParenthesesString(string name, string[] attributes, bool prependSpace, string expected)
    {
        var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

        var result = itemWithNameAndAttributes.AttributesToParenthesesString(prependSpace);

        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Name", new [] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }, "Name (Item 1) (Item 2) (Item 3) (Item 4) (Item 5)")]
    [InlineData("Name", new string[0], "Name")]
    public void Verify_ToString(string name, string[] attributes, string expected)
    {
        var itemWithNameAndAttributes = new ItemWithNameAndAttributes(name, attributes);

        var result = itemWithNameAndAttributes.ToString();

        Assert.Equal(expected, result);
    }
}

在编写该示例时,我注意到--testing隐式测试Verify_AttributesToParenthesesString有点多余。如果存在只是为了支持,那么它是一个实现细节。可以通过删除和更改对.Verify_ToStringToStringAttributesToParenthesesStringAttributesToParenthesesStringToStringVerify_AttributesToParenthesesStringAttributesToParenthesesStringprotected


推荐阅读