簡體   English   中英

對於普通班級來說,進行單元測試覆蓋是一種好習慣

[英]Is it good practice to do unit test coverage for even plain classes

這是一個完全沒有行為的類的例子。 所以問題是我應該為它做單元測試覆蓋,因為我認為它沒有必要,因為它確實有任何行為。

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

我的代碼覆蓋率結果抱怨我沒有為該課程做過任何報道

我從不為這些做過測試。 沒有行為要測試。

如果有任何非平凡的行為代碼(也許是驗證代碼),那么我會為它編寫一個測試。

我從Martin Fowler那里找到了這篇有趣的文章:

測試覆蓋率是查找未經測試的代碼庫部分的有用工具。 測試覆蓋率作為測試有多好的數字陳述幾乎沒用。

===

對象導師的這個有趣的引用:

它可能不是強制性的,如果您的目標是100%覆蓋率,您將專注於該目標,而不是專注於為代碼行為編寫最佳測試。

我可以接受或離開它。 但是,雖然現在幾乎沒有明顯的好處,但如果程序員后來出現,將其轉換為傳統的,成員字段支持的屬性,並在簡單的情況下摸索實現,您將被覆蓋。

但我個人實際上並不打擾,因為我的時間有限,而且我有更重要的測試要寫,這將為我的降壓提供更大的幫助。

Kent Beck在他的“按示例進行測試驅動開發”中列出了您應該測試的內容:

  • 條件語句
  • 循環
  • 操作
  • 多態性

你的班級沒有這些。

通常會問自己一個問題, “如果我用單元測試覆蓋這些代碼,我會得到什么?” 如果“指向某些指標”是您可以提出的唯一答案,則可能不值得為此類代碼編寫測試。 你會花時間 ,產生額外的代碼 ,什么都得不到(代碼覆蓋“點”沒什么價值 - 至少在這種情況下)。

另外,看看這兩個問題(它們都解決了類似的問題,答案主要解決一個重要問題 - [在大多數情況下]總會有人為你所做的事付錢 - 並且有人可能不會很高興知道你花時間提高評級 ,因為這是它本質上是):

定論? 我同意其他人說你不應該測試這些課程。

這並不是一個壞主意......例如,假設你開發了一個后端來存儲未來的數據(例如數據庫)。 你可以替換泛型get; set; get; set; 使用其他自定義功能調用。 進行單元測試可確保始終執行代碼,並且不會在轉換中引入錯誤。

即使是一個非常簡單的測試,它會檢查您是否可以創建對象,設置字段以及讀回相同的值,這表明您正在使用預期的行為來執行代碼。 即使對您來說顯而易見,該代碼的未來開發人員也可以使用該示例進行繪制,並確保所有更改都符合您的原始設計目標。

我也是這樣看待:在開發測試時幾乎沒有任何傷害,具有一些非常可能的長期優勢。 現在只需幾分鍾就可以跟蹤線下引入的問題。

替代方案:您沒有覆蓋此特定類的事實暗示有一些代碼使用此類,並且該代碼也沒有測試覆蓋率。 我先解決這個問題,看看是否需要更多的測試。

至於測試這樣的僅數據對象:如果此對象是庫/單元的外部合同的一部分,我肯定會添加顯式測試。 您承諾您的代碼將返回/使用此數據。 如果沒有測試驗證您可以更改代碼的內部並更改此類,您將違背承諾,沒有任何阻止您。

如果您只保留數據傳輸對象這樣的類,可以說您不需要對它們進行單元測試。 但是,只要您開始添加行為,就應該編寫相應的測試。

查看可以作為構建過程的一部分返回的代碼覆蓋率也可以幫助發現任何缺失的測試。

作為一個簡短的回答,我會說“是”,對於普通課程,你可以在不獲得報道的情況下逃脫。

單元測試的目的是保持你的代碼“固定”,這樣如果你改變了實現,你知道你沒有破壞任何東西,或者如果你確實破壞了某些東西,你就會立即知道你破壞了什么。

這樣做的另一個好處是知道您當前編寫的代碼您希望它執行的操作,但這不是(或不一定)單元測試的主要目標。 單元測試使您可以放心地更改代碼。

如果上面這樣的類沒有經過單元測試,那么可以打破類,而不會導致任何測試失敗。 例如:

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get { return "Smith"; } set { FirstName = value; } }
    public Address Address { get; set; }
}

通過單元測試,您可以知道整個代碼庫中沒有發生過類似的事情。 (這是具體的例子可能?也許不是,但這樣的事情是非常有可能的,基本上innevitable。)

只需要進行四次簡單的單元測試,就可以使這段代碼“修復”,因為它知道如果沒有測試失敗就不能改變它的行為*:

[TestMethod]
public void TestId() {
   var emp = new Employee { Id = 3 };
   Assert.AreEqual(3, emp.Id);
}

[TestMethod]
public void TestFirstName() {
   var emp = new Employee { FirstName = "asdf" };
   Assert.AreEqual("asdf", emp.FirstName);
}

[TestMethod]
public void TestLastName() {
   var emp = new Employee { LastName = "asdf" };
   Assert.AreEqual("asdf", emp.LastName);
}

[TestMethod]
public void TestAddress() {
   var address = new Address();
   var emp = new Employee { Address = address };
   Assert.AreEqual(address, emp.Address);
}

(*可能除了用於模擬您用於測試的值的破壞實現的側面案例)

我不會在這里實現它,但你也可以使用反射來簡化這些類型的測試。 例如,您可以相對容易地構建一些允許您執行以下操作的內容:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      Assert.IsTrue(
         SimplePropertyTester.Create(
            new SimplePropertyTestCollection<Employee> {
               { emp => emp.Id, 3 },
               { emp => emp.FirstName, "asdf" },
               { emp => emp.LastName, "1234" },
               { emp => emp.Address, new Address() }
            }
         ).Test()
      );
   }
}

您失去了將每個屬性放在自己的測試中的好處,但您可以非常輕松地修改測試集。

您還可以為每個單元測試構建一個單獨的測試器,然后將測試分開,但與手動編寫測試並沒有太大區別,最后您最終編寫完全相同的代碼行。一遍又一遍。

您可以做的一件事是將Console.WriteLine語句放在Test()方法中,然后您應該能夠查看一些文本輸出以更快地查明問題。

編輯:其實我現在已經看到如下所示:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      var factory = SimplePropertyTestFactory.Create<Employee>();
      new SimplePropertyTestCollection<Employee> {
         factory.IntTest(emp => emp.ID),
         factory.StringTest(emp => emp.FirstName),
         factory.StringTest(emp => emp.LastName),
         factory.ReferenceTest(emp => emp.Address)
      }.Test();
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM