3

i'm setting-up a unit test using the Moq framework.

I have an interface describing the class like so:

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

For ensuring the RemoveSource-Method is called I implemented a base class where the remove is called in the dispose method.

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();
    }
}

When mocking the ISourceFileLocation there is no default implementation, so for testing i wanna implement testing on the baseclass where the concrete class should inherit from.

When mocking the baseclass my test expects that the RemoveSource-Method is virtual which breaks my idea of ensuring the method will be called!!

Is this a lack of the framework, are there better frameworks or ways to test this, or is this a problem with my code and should I rethink my design?

kind regards.

The testmethods:

    [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);
    }
Matt Cole
  • 2,491
  • 17
  • 21
Luuk Krijnen
  • 1,180
  • 3
  • 14
  • 37

1 Answers1

6

I think you may be misusing Moq in this example because you are using the same mock object for your system under test (SUT), and to perform your behavior verification. Your tests are essentially checking whether SourceFileBase calls itself or not. Typically you would use Moq to verify calls to dependencies of the SUT.

The code in SourceFileBase isn't unit test friendly, because it is using static methods on the File class directly. To make it unit testable, you would need to abstract this somehow (e.g. see this question).

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();
    }
}

Doing so would allow you to test that both Dispose() and RemoveSource() delete the file.

// 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));
Community
  • 1
  • 1
Matt Cole
  • 2,491
  • 17
  • 21