在单元测试中,您是否验证并断言?

Sta*_*low 11 unit-testing moq

我在我的单元测试项目中使用Moq.我在网上看到的大多数单元测试示例结束时,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);
Run Code Online (Sandbox Code Playgroud)

任何想法?谢谢.

Ada*_*hah 27

不,在大多数情况下你不应该同时使用它们(总是有例外).原因是你应该只测试测试中的一个问题,即可维护性,可读性和其他一些原因.因此,在测试中应该是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";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我用一个例子更新了答案.您甚至可以复制该代码并在visual studio中的单元测试文件中运行它.您必须添加对Moq Nuget包的引用 (2认同)

mmi*_*uva 7

是的你应该调用断言.

VerifyAll()将声明所有SetUp()调用都被实际调用.

VerifyAll()不会确认您的学生对象已注册.因为SetUp()您的测试用例中没有调用,我认为VerifyAll()不会验证任何内容.


lev*_*nis 5

我绝对希望在单元测试中并排查看VerifyAssert使用.断言用于验证已正确设置被测系统的属性,而Verify用于确保已正确调用被测系统所接受的任何依赖项.使用时,Moq我倾向于在显式验证设置而不是使用VerifyAll全部捕获方面犯错误.这样你就可以使测试的目的更加清晰.

我在上面的代码中假设您对学生资料库的调用返回一个布尔值来表明该学生已注册?然后你在student对象上设置该值?在这种情况下,需要添加一个有价值的设置,您有效地说,当调用学生存储库方法时,它将返回true.然后,你Assertstudent.IsRegistered是真的,以确保您从库中返回值正确设置属性,你Verify该库调用方法与你期望的输入.