[英]C# Unit Testing - Should you unit test something in a derived class that is taken care of in a base class?
[英]Unit testing base and derived class
所以我有2节课。 ItemWithAttributes
和ItemWithNameAndAttributes
(源自 1st)。
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
派生时,我将有更多相同的测试并重新测试基类。 我觉得对于我的小班级来说,它很快变得非常复杂。
根据示例代码,我没有看到通过继承进行整合的好方法。 测试确实遵循几乎相同的结构(实例化一个对象,对该对象做一些事情,验证结果——即,Arrange、Act、Assert),但实现细节是有意义的不同(“act”步骤是相同的,但构造函数和预期结果不同)。 在这种情况下,测试和断言框架已经完成了尽可能多的重复数据删除。
注意:使用某些单元测试框架(我主要使用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);
}
}
在编写该示例时,我注意到Verify_AttributesToParenthesesString
与Verify_ToString
--testing ToString
隐式测试AttributesToParenthesesString
有点多余。 如果AttributesToParenthesesString
存在只是为了支持ToString
,那么它是一个实现细节。 可以通过删除Verify_AttributesToParenthesesString
并将AttributesToParenthesesString
的访问权限更改为protected
来简化代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.