2017-06-09 193 views
1

我正在嘗試編寫一些類的測試。我想要測試的類使用不同的存儲庫來從我的數據庫中獲取和保存內容。單元測試用存根和模擬

一個簡單的例子

public class MyClass 
{ 
    private readonly IGroupRepository _groupRepo; 

    public MyClass(IGroupRepository groupRepo){ 
    _groupRepo = groupRepo; 
    } 

    public void Execute(PersonInfo personInfo, string id){ 
    var group = _groupRepo.GetById(id); 

    var person = group.Persons.First(p=> p.Id == personInfo.Id); 

    person.FirstName = personInfo.FirstName; 
    person.LastName = personInfo.LastName; 

    _groupRepo.Save(group);  
    } 
} 

我想要做的就是確保內容被保存到數據庫是正確的。

所以我有這樣的一個單元測試:

[TestMethod] 
public void TestMethod(){ 
    var groupId = "ABC"; 
    var personId = 1; 

    ver personInfo = new PersonInfo() 
    { 
     Id = personId, 
     FirstName = "Sam", 
     LastName = "Smith" 
    } 

    var groupStub = new Mock<IGroupRepository>; 
    groupStub.Setup(x=> x.GetById(groupId)).Returns(new Group(){ 
      Id = groupId, 
      Persons = List<Person>() 
      { 
       new Person() 
       { 
        Id = personId, 
        FirstName = "George", 
        LastName = "Bolton", 
       } 
      } 
     } 
    }); 

    var myClass = new MyClass(); 
    myClass.Execute(personInfo, groupId); 

    var group = groupStub.GetById(groupId); 
    var person = group.Persons.First(p=> p.Id == personId); 

    Assert.AreEqual(personInfo.FirstName, person.FirstName); 
} 

我認爲這是很好,但後來我讀多了起來就可以了,我看你不應該斷言在子,其我想我在我的斷言中做了什麼?我從存根中獲取信息,然後在結果上使用Assert?

所以我不確定這是否是正確的測試方法。如果沒有,爲什麼和什麼是正確的方法?

回答

1

是的,你是正確的,寫測試的方式有問題。實際上,您並未測試MyClass。你正在測試你使用的模擬框架的作品。作爲證據,請註釋使用MyClass的兩行並再次運行測試。它仍然會通過:

[TestMethod] 
public void TestMethod() 
{ 
    var groupId = "ABC"; 
    var personId = 1; 

    ver personInfo = new PersonInfo() 
    { 
     Id = personId, 
     FirstName = "Sam", 
     LastName = "Smith" ` 
    } 

    var groupStub = new Mock<IGroupRepository>; 
    groupStub.Setup(x=> x.GetById(groupId)).Returns(new Group(){ 
      Id = groupId, 
      Persons = List<Person>() 
      { 
       new Person() 
       { 
        Id = personId, 
        FirstName = "George", 
        LastName = "Bolton", 
       } 
      } 
     } 
    }); 

    // var myClass = new MyClass(); 
    // myClass.Execute(personInfo, groupId); 

    var group = groupStub.GetById(groupId); 
    var person = group.Persons.First(p=> p.Id == personId); 

    Assert.AreEqual(personInfo.FirstName, person.FirstName); 
} 

什麼通常幫助我編寫單元測試,首先問自己我真正測試的是什麼行爲。在這種特殊情況下,我相信你想測試一下,當調用MyClass.Execute, 時,你期望IGroupRepository.Save被調用,並且人名的改變。

寫在模擬框架我所熟悉的(NSubstitute)這一說法,看起來像這樣:

groupStub.Received().Save(
    Arg.Is<Group>(group => 
    { 
     return groupId.Id == groupId && 
      group.Persons[0].Id == personId && 
      group.Persons[0].FirstName == "Sam" && 
      group.Persons[0].LastName == "Smith"; 
    }); 

應該有在使用模擬框架類似的東西。

1

建議您不要測試保存到 數據庫是否正確。這是比單元 測試更多的集成測試,它超出了你的課程範圍。

可能有很多原因導致數據沒有正確保存在數據庫中,但是您的班級表現得應該是這樣,例如網絡問題,但是如果失敗,您的UT將不會正確。

相反,您應該測試自己的類,以瞭解在數據庫插入失敗或發生某種異常時類的行爲方式。然後使用你的模擬框架來模擬具有這些期望的存儲庫,並在你的類的測試中相應地聲明。

一些好的讀數herehere

1

你不應該測試是要實現單元測試類中使用另一個模塊/類的邏輯。

您應該只按照業務邏輯的說法測試/驗證對該模塊的調用是否被調用。您只應該專注於該類的業務邏輯,僅針對您正在編寫單元測試用例。

這裏你的情況IGroupRepository是另一個模塊/類,而不是你正在編寫單元測試的那個。相反,如果您想驗證數據是否正在保存,那麼您應該將其包含在您爲IGroupRepository實施的另一個測試案例中。

但是不建議用於單元測試的數據保存,它被認爲是集成測試的一部分。