我正在开始使用c#,我被要求做一个任务,包含编写一个setter的单元测试和检查它的输出。我被要求做一个任务,包含编写一个setter的单元测试并检查其输出。我不明白为什么要测试一些不包含任何逻辑的琐碎的东西,这里有一个例子(SetKeywords()是要测试的方法)。
public struct Keyword
{
private string keyword;
private KeywordTypes type;
public Keyword(string keyword, KeywordTypes Type =
KeywordTypes.String)
{
this.keyword = keyword;
this.type = Type;
}
public string GetString()
{
return this.keyword;
}
public KeywordTypes WhichType()
{
return this.type;
}
}
public class ShopParser
{
private Keyword[] keywords = new Keyword[0];
public void **SetKeywords**(Keyword[] tags)
{
keywords = tags;
}
}
public Keyword[] GetKeywords()
{
return this.keywords;
}
public static KeywordPair[] ExtractFromTaG(ShopParser parser, string
serializedInput)
{
var findings = new KeywordPair[0];
foreach (var keyword in parser.GetKeywords())
{
var start = serializedInput.IndexOf(keyword.GetStart());
// Check if keyword is in input string, if not continue
with next keyword.
if (start <= -1) continue;
var end = serializedInput.LastIndexOf(keyword.GetEnd());
// Extract the thing between the tags. Tag excluded
start += keyword.GetStart().Length;
var substring = serializedInput.Substring(start, end -
start);
// Add substring to result list
var tmp = new KeywordPair[findings.Length + 1];
var i = 0;
for (; i < findings.Length; ++i)
{
tmp[i] = findings[i];
}
tmp[i] = new KeywordPair(keyword, substring);
findings = tmp;
}
return findings;
}
}
如何测试?
当你调用 SetKeywords
它应该做一些事情。现在,它设置了内部数组 keywords
. 所以,你需要问自己的问题是,你怎么能确定它做到了这一点?那么你有一个 GetKeywords
方法返回内部数组,所以我们可以用它来进行测试,如下图。
[TestClass]
public class ShopParserTests
{
[TestMethod]
public void SetKeyWords__WhenGivenAnArray__MustSetTheInternalArray()
{
// Arrange
var k1 = new Keyword("One", KeywordTypes.String);
var k2 = new Keyword("Two");
var parser = new ShopParser();
var keys = new Keyword[] { k1, k2 };
// Act
parser.SetKeywords(keys);
// Assert
Keyword[] keysReturned = parser.GetKeywords();
Assert.AreEqual(keysReturned[0].GetString(), k1.GetString());
Assert.AreEqual(keysReturned[0].WhichType(), k1.WhichType());
Assert.AreEqual(keysReturned[1].GetString(), k2.GetString());
Assert.AreEqual(keysReturned[1].WhichType(), k2.WhichType());
// More tests
}
}
一些建议
请记住,你可能需要根据你的需求编写更多的测试。例如,如果用户这样做了怎么办。
Keyword[] keysReturned = parser.GetKeywords();
keys[0] = new Keyword();
你想允许这样做吗?
另外,在C#中,你的类可以被简化并利用属性。所以你的 Keyword
和ShopParser类要这样写。
public struct Keyword
{
public Keyword(string keyword, KeywordTypes type =
KeywordTypes.String)
{
this.TheKeyword = keyword;
this.KeyType= type;
}
public string TheKeyword { get; private set; }
public KeywordTypes KeyType { get; private set; }
}
public class ShopParser
{
public void SetKeywords(Keyword[] tags)
{
this.KeyWords = tags;
}
public Keyword[] KeyWords { get; private set; }
}
缺乏复杂的代码并不意味着该类的作者没有任何设计上的决定,这些决定应该通过单元测试来验证和保护。例如,你为集合中的项目选择了值类型,这使得一些行为不可能实现,而一些行为则是微不足道的--测试的目的是为了澄清这个类实现了那个 设计决定 适当并保护 行径 类的单元测试,以备将来修改。
为集合类型的属性设置器进行单元测试(与值类型不同的是,集合类型的属性设置器是一个单元测试。int
)实际上是 非同小可 因为我们必须验证类的契约是否被定义并得到正确的支持--setter是对一个集合进行复制还是引用现有的集合,它是进行深复制还是浅复制?正确地测试每一种情况绝对不是一项琐碎的任务。(同样在较小的程度上适用于所有引用类型的属性,但在非集合的情况下,对行为的期望通常与默认值更一致)。
所以你要做的是 之前 编写测试是为了决定你的集合属性的行为--它是在设置时进行复制还是引用原始的实时实例。如果集合是引用类型的(问题中不是这种情况),你还需要决定它是进行浅层复制还是深层复制(深层复制是不寻常的)。
在你做出决定后,写测试来验证就有点小题大做了。你添加以下测试。
我们可能需要额外的测试来验证作为getter结果返回的集合是否按照类作者的设计行为--特别是对结果集合的修改是否反映在类的状态中(getter返回状态的浅层拷贝或直接暴露内部状态,如问题所示)。
请注意,不鼓励为集合属性设置器--请参见 CA2227:集合属性应只读。. 所以问题中的代码有点遵循建议,但更好的名称,如 "AddKeywords""ReplaceKeywords "将澄清行为,而不是一般的 "设置"。