单元测试模拟框架是否会影响您编程的方式?

Luu*_*nen 3 c# unit-testing moq

我正在使用Moq框架进行单元测试.

我有一个描述类的接口,如下所示:

public interface ISourceFileLocation : IFileLocation, IDisposable
{
    bool RemoveAfterTransfer { get; set; }
    void RemoveSource();
    //.....
}
Run Code Online (Sandbox Code Playgroud)

为了确保调用RemoveSource-Method,我实现了一个基类,其中在dispose方法中调用remove.

public abstract class SourceFileBase : ISourceFileLocation
{
    //......

    public bool RemoveAfterTransfer { get; set; }

    public void RemoveSource()
    {
        if (File.Exists(Uri.AbsolutePath))
        {
            File.Delete(Uri.AbsolutePath);
        }
    }

    public void Dispose()
    {
        if (this.RemoveAfterTransfer)
            this.RemoveSource();
    }
}
Run Code Online (Sandbox Code Playgroud)

模拟ISourceFileLocation时没有默认实现,因此对于测试我想在具体类应该继承的基类上实现测试.

在模拟基类时,我的测试期望RemoveSource-Method是虚拟的,这打破了我确保调用方法的想法!

这是缺乏框架,有更好的框架或方法来测试这个,或者这是我的代码的问题,我应该重新考虑我的设计?

亲切的问候.

测试方法:

    [TestCategory("Source")]
    [TestMethod]
    public void CheckIfRemoveSourceMethodIsCalled()
    {
            //ARRANGE
            var mockSourceLocation = new Mock<SourceFileBase>();
            mockSourceLocation.Object.RemoveAfterTransfer = true;
            mockSourceLocation.Setup(x => x.RemoveSource());
            //ACT
            mockSourceLocation.Object.Dispose();
            /ASSERT
            mockSourceLocation.VerifyAll();
    }

    [TestCategory("Source")]
    [TestMethod]
    public void CheckIfRemoveSourceMethodIsNotCalled()
    {
            //ARRANGE
            var mockSourceLocation = new Mock<SourceFileBase>();
            mockSourceLocation.Object.RemoveAfterTransfer = false;
            //ACT
            mockSourceLocation.Object.Dispose();
            //ASSERT
            mockSourceLocation.Verify(x=>x.RemoveSource(), Times.Never);
    }
Run Code Online (Sandbox Code Playgroud)

Mat*_*ole 6

我认为您可能在此示例中滥用Moq,因为您正在为被测系统(SUT)使用相同的模拟对象,并执行行为验证.您的测试主要是检查是否SourceFileBase自己调用.通常,您将使用Moq来验证对SUT 依赖性的调用.

代码SourceFileBase不是单元测试友好的,因为它File直接在类上使用静态方法.为了使其可单元测试,您需要以某种方式对其进行抽象(例如,请参阅此问题).

public abstract class SourceFileBase : ISourceFileLocation
{
    private readonly IFileSystem _fileSystem;

    public SourceFileBase(IFileSystem fileSystem)
    {
        _fileSystem = fileSystem;
    }

    ...

    public void RemoveSource()
    {
        _fileSystem.DeleteFile(Uri.AbsolutePath);
    }

    public void Dispose()
    {
        RemoveSource();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做可以让你测试两者Dispose()RemoveSource()删除文件.

// Arrange
var mockFileSystem = new Mock<IFileSystem>();
var sut = new Mock<SourceFileBase>(mockFileSystem.Object);
sut.RemoveAfterTransfer = true;
sut.Uri = myTestUri;

// Act
sut.Dispose();

// Assert
mockFileSystem.Verify(f => f.DeleteFile(myTestUri.AbsolutePath));
Run Code Online (Sandbox Code Playgroud)