Правильно ли я использую mocks?

#c# #tdd #mocking #moq

#c# #tdd #издевательство #moq

Вопрос:

Я новичок в mocking и впервые пробую moq. Мне интересно, могу ли я написать тест только с использованием mocks?

 public class FileCopierTests
{
    private string path = AppDomain.CurrentDomain.BaseDirectory;

    [Fact]
    public void Copy_starts_copying_when_event_is_fired_returns_true()
    {
        var fullyQualifiedFileName = string.Format(@"{0}....IntegrationTestData.xls", this.path);
        var destFileName = Path.GetTempPath()   "66768c06-d1c4-4416-be81-767f36abeeb1.xls";

        var copierMock = new Mock<IFileCopier>();
        var watcherMock = new Mock<IFileWatcher>();

        copierMock.Setup(cp => cp.Copy(fullyQualifiedFileName, destFileName)).Raises(
            ev => ev.CopyingFinished  = null, destFileName);

        watcherMock.Object.Changed  = arg => copierMock.Object.Copy(arg, destFileName);   

        watcherMock.Raise(e => e.Changed  = null, fullyQualifiedFileName);

        copierMock.VerifyAll();
    }
}
  

Это классы и интерфейсы, которые я хочу протестировать,

 public interface IFileCopier
{
    event Action<string> CopyingFinished;

    void Copy(string fqFileName, string destFileName);
}

public class FileCopier : IFileCopier
{
    private ReaderWriterLockSlim @lock = new ReaderWriterLockSlim();

    public event Action<string> CopyingFinished;

    public void Copy(string fqFileName, string destFileName)
    {
        this.@lock.EnterWriteLock();
        try
        {
            File.Copy(fqFileName, destFileName, true);

            if (this.CopyingFinished == null)
            {
                return;
            }

            this.CopyingFinished(destFileName);
        }
        finally
        {
            this.@lock.ExitWriteLock();
        }
    }
}

public interface IFileWatcher
{
    event Action<string> Changed;
}

public class FileChangeWatcher : IFileWatcher
{
    public FileChangeWatcher(FileSystemWatcher eyes)
    {
        this.Eyes = eyes;
        this.Eyes.Changed  = this.OnChangedEvent;
    }

    protected FileSystemWatcher Eyes { get; set; }

    public event Action<string> Changed;

    private void OnChangedEvent(object sender, FileSystemEventArgs eventArgs)
    {
        if (this.Changed == null)
        {
            return;
        }

        this.Changed(eventArgs.FullPath);
    }
}
  

Ответ №1:

То, что вы делаете, неверно — когда вы пишете тест, используя только mocks, вы на самом деле ничего не тестируете!

Вместо этого вы хотите ввести часть вашего кода, не являющегося mocked, кода, который использует объекты, которые вы заменяете mocks .

Две важные вещи, которые дает вам использование mocks (и, в частности, mocking framework, таких как moq), это:

1 — Изоляция

2 — Проверяемость

Под изоляцией я подразумеваю, что в вашем случае вы не хотите копировать файл каждый раз, когда вы тестируете действия в своем классе копирования файлов. Итак, вы заменяете настоящий файловый копировальный аппарат чем-то, что притворяется файловым копировальным аппаратом.

Под проверяемостью я подразумеваю, что часто классы не имеют никакого способа сообщить вам, были ли они вызваны. Обычно это хорошо, поскольку сообщать другим людям, были ли они вызваны, не является частью их работы, но в сценариях тестирования вам нужна эта информация — ожидания в moq позволяют вам ее собирать.


В этом случае похоже, что у вас есть что-то, что вызывает событие, а затем что-то, что прослушивает это событие и вызывает метод копирования в вашем FileCopier.

Итак, вы хотите смоделировать источник события (или правильно вызвать конкретный источник события), а затем вызвать это событие.

Затем вам понадобится второй макет — макет FileCopier, который ожидает, что его метод копирования будет вызван с правильными параметрами. Этот макет FileCopier должен передаваться вызывающему его классу (внедрение зависимостей), и это позволяет вам подтвердить, что метод копирования вызывается вашим реальным кодом.

Комментарии:

1. итак, мой тест не завершен. Мне нужно было бы передать объект обоих mocks в реальный класс, например FileSurveillance (IFileWatcher watcher, IFileCopier copier) и подтвердить / проверить состояние и / или поведение реального класса

2. @mrt181 точно — ознакомьтесь с примерами, приведенными на сайте moq, и этим сообщением stephenwalther.com/blog/archive/2008/06/12 /… для получения дополнительной информации. Также стоит прочитать о внедрении зависимостей и инверсии управления

Ответ №2:

У вас могут быть только mocks, но это означает, что вы на самом деле ничего не тестируете.

В этом случае ссылки на copier были бы лучше, если бы они были реальным классом, таким образом, вы можете проверить, что происходит, когда watchermock событие отключается.