![](/img/trans.png)
[英]Should protected methods be unit-tested? How to avoid repetitive testing?
[英]unit testing public methods with tested internal methods
我发现自己陷入了很多这种模式,我编写了一个由非常小的方法组成的类,这些方法完全由我的单元测试来完成。 然后我发现我需要构建另一个调用这些方法的方法,我必须为此编写一个更复杂的单元测试 - 一个简单的例子就是说明性的:
namespace FooRequest
{
static public class Verifier
{
static public bool IsValid(string request)
{
return (!IsAllCaps(request) && !ContainsTheLetterB(request));
}
static internal bool IsAllCaps(string request)
{
return (request.Equals(request.ToUpper()));
}
static internal bool ContainsTheLetterB(string request)
{
return request.ToLower().Contains("b");
}
}
}
对于代码,我会编写单元测试来涵盖这样的两个内部方法:
namespace UnitTest
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FooRequest;
public class VerifierTest
{
[TestClass]
public class ContainsTheLetterB
{
[TestMethod]
public void ShouldReturnTrueForStringContainsB()
{
Assert.IsTrue(Verifier.ContainsTheLetterB("burns"));
}
[TestMethod]
public void ShouldReturnFakseForStringDoesNotContainB()
{
Assert.IsFalse(Verifier.ContainsTheLetterB("urns"));
}
}
[TestClass]
public class IsAllCaps
{
[TestMethod]
public void ShouldReturnTrueForStringIsAllCaps()
{
Assert.IsTrue(Verifier.IsAllCaps("IAMALLCAPS"));
}
[TestMethod]
public void ShouldReturnFakseForStringDoesNotContainB()
{
Assert.IsFalse(Verifier.IsAllCaps("IAMnotALLCAPS"));
}
}
}
}
对于公共方法,我真的只想测试“如果你调用的方法返回false,那么返回false” - 我很难设置输入以强制我的内部方法返回true或false - 我的测试这个方法应该不关心它调用的内部方法(对吧?)
[TestClass]
public class IsValid
{
[TestMethod]
public void ShouldReturnFalseForInvalidStringBecauseContainsB()
{
Assert.IsFalse(Verifier.IsValid("b"));
}
[TestMethod]
public void ShouldReturnFalseForInvalidStringBecauseIsAllCaps()
{
Assert.IsFalse(Verifier.IsValid("CAPS"));
}
[TestMethod]
public void ShouldReturnTrueForValidString()
{
Assert.IsTrue(Verifier.IsValid("Hello"));
}
}
显然对于这个例子来说,这并不算太糟糕,但是当有很多内部方法并且输入配置非常简单时,测试我的公共“Is This Input Valid”方法会变得复杂。
我应该为我的所有内部方法创建一个接口,然后将其存根以进行测试,还是有更简洁的方法?
我正在输入评论,但它太大了。 我认为你处于违反SRP的边缘,但你肯定违反了开放/封闭原则。 如果需要更改验证字符串的方式,则需要修改验证程序类。
我会接近这个与@seldary有点不同,但不是很多......
public interface IStringRule
{
bool Matches(string request);
}
public class AllCapsRule : IStringRule
{
public bool Matches(string request)
{
//implement
}
}
public class IsContainingBRule : IStringRule
{
public bool Matches(string request)
{
//implement
}
}
public class Verifier
{
private List<IStringRule> Rules;
public Verifier(List<IStringRule> rules)
{
Rules = rules;
}
public bool IsValid(string request)
{
return (!Rules.Any(x=>x.Matches(request) == false));
}
}
现在你的verifer可以扩展,但是接近修改。 您可以根据需要添加任意数量的新规则,但实现不会更改。 测试验证程序就像传入一些返回任意true和false值的模拟字符串规则一样简单,并确保验证程序返回适当的结果。
每个IStringRule都会像您一样单独进行测试。
更简洁的方式如下:
Verifier
类重构为三个类,在本例中为每个方法一个: Verifier
, AllCapsChecker
, LetterBChecker
。 Verifier
。 VerifierTests
类应该将两个依赖项排列并注入Verifier
,并仅测试Verifier
逻辑 (在这种情况下只测试逻辑运算符)。 在这里你可以找到Verifier
和VerifierTests
类的改编,只是为了得到这个想法(我在这里使用了Moq):
namespace FooRequest
{
public interface IAllCapsChecker
{
bool IsAllCaps(string request);
}
public interface ILetterBChecker
{
bool IsContainingB(string request);
}
public class Verifier
{
private readonly IAllCapsChecker m_AllCapsChecker;
private readonly ILetterBChecker m_LetterBChecker;
public Verifier(IAllCapsChecker allCapsChecker, ILetterBChecker letterBChecker)
{
m_AllCapsChecker = allCapsChecker;
m_LetterBChecker = letterBChecker;
}
public bool IsValid(string request)
{
return (!m_AllCapsChecker.IsAllCaps(request) && !m_LetterBChecker.IsContainingB(request));
}
}
[TestClass]
public class IsValid
{
[TestMethod]
public void ShouldReturnFalseForInvalidStringBecauseContainsB()
{
var allCapsMock = new Mock<IAllCapsChecker>();
allCapsMock.Setup(checker => checker.IsAllCaps("example")).Returns(true);
var letterBChecker = new Mock<ILetterBChecker>();
letterBChecker.Setup(checker => checker.IsContainingB("example")).Returns(true);
var verifier = new Verifier(allCapsMock.Object, letterBChecker.Object);
Assert.IsFalse(verifier.IsValid("example"));
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.