[英]In a unit test, do you verify and assert?
我在我的單元測試項目中使用Moq。 我在網上看到的大多數單元測試示例以someMock.VerifyAll();
結尾someMock.VerifyAll();
我想知道在VerifyAll()
之后斷言是否可以。 所以,例如,
//Arrange
var student = new Student{Id = 0, Name="John Doe", IsRegistered = false};
var studentRepository = new Mock<IStudentRepository>();
var studentService= new StudentService(studentRepository.Object);
//Act
studentService.Register(student); //<-- student.IsRegistered = true now.
//Verify and assert
studentRepository.VerifyAll();
Assert.IsTrue(student.IsRegistered);
任何想法? 謝謝。
不,在大多數情況下你不應該同時使用它們 (總是有例外)。 原因是你應該只測試測試中的一個問題,即可維護性,可讀性和其他一些原因。 因此,在測試中應該是Verify(VerifyAll)或Assert,並相應地命名測試。
看看Roy Osherove關於它的文章:
http://osherove.com/blog/2005/4/3/a-unit-test-should-test-only-one-thing.html
VerifyAll
用於確保調用某些方法以及調用多少次。 你使用mocks
。
Assert
用於驗證從您正在測試的方法返回的結果。 你使用Stubs
。
Martin fowler有一篇很棒的文章解釋了模擬和存根之間的區別。 如果你了解它,你會更好地了解它們。
http://martinfowler.com/articles/mocksArentStubs.html
更新:使用Moq的模擬vs存根的示例,如下面的注釋所示。 我使用過驗證,但您也可以使用VerifyAll。
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
...
[TestClass]
public class UnitTest1
{
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method calls
/// Repository GetName method once when Id is greater than Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(12);
// Assert
mockEntityRepository.Verify(
m => m.GetName(It.IsAny<int>()), Times.Once);
}
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method
/// doesn't calls Repository GetName method when Id is Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(0);
// Assert
mockEntityRepository.Verify(
m => m.GetName(It.IsAny<int>()), Times.Never);
}
/// <summary>
/// Test using Stub to Verify that GetNameWithPrefix method
/// returns Name with a Prefix
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
{
// Arrange
var stubEntityRepository = new Mock<IEntityRepository>();
stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
.Returns("Stub");
const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
var entity = new EntityClass(stubEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(12);
// Assert
Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
}
}
public class EntityClass
{
private IEntityRepository _entityRepository;
public EntityClass(IEntityRepository entityRepository)
{
this._entityRepository = entityRepository;
}
public string Name { get; set; }
public string GetNameWithPrefix(int id)
{
string name = string.Empty;
if (id > 0)
{
name = this._entityRepository.GetName(id);
}
return "Mr. " + name;
}
}
public interface IEntityRepository
{
string GetName(int id);
}
public class EntityRepository:IEntityRepository
{
public string GetName(int id)
{
// Code to connect to DB and get name based on Id
return "NameFromDb";
}
}
是的你應該調用斷言。
VerifyAll()
將斷言所有SetUp()
調用實際上都被調用了。
VerifyAll()
不會確認您的學生對象已注冊。 因為在您的測試用例中沒有SetUp()
調用,我認為VerifyAll()
沒有驗證任何內容。
我絕對希望看到Verify
和Assert
在單元測試中並排使用。 斷言用於驗證已正確設置被測系統的屬性,而Verify
用於確保已正確調用被測系統所接受的任何依賴項。 使用Moq
我傾向於明確驗證設置而不是使用VerifyAll
catch-all。 這樣你就可以使測試的目的更加清晰。
我在上面的代碼中假設您對學生資料庫的調用返回一個布爾值來表明該學生已注冊? 然后你在student
對象上設置該值? 在這種情況下,需要添加一個有價值的設置,您有效地說,當調用學生存儲庫方法時,它將返回true。 然后Assert
student.IsRegistered
為true以確保您已從存儲庫返回值中正確設置屬性,並Verify
使用您期望的輸入調用存儲庫方法。
在模擬測試中斷言和驗證都沒有任何本質上的錯誤,盡管依賴於被調用的實際方法的斷言可能會失敗,因為模擬方法與真實方法沒有相同的效果。
在您的示例中,它可能很好,因為只有存儲庫被模擬,並且學生狀態的更改可能在服務中完成。
驗證和斷言是否應該在同一測試中完成在某種程度上是一種品味問題。 實際上,驗證是檢查是否正確調用了存儲庫,並且斷言正在檢查是否對該實體進行了正確的更改。 由於這些是單獨的問題,我會將它們分開進行測試,但這可能就是我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.