![](/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.