Я правильно использую макеты? - PullRequest
2 голосов
/ 04 ноября 2011

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

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}\..\..\Integration\TestData.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);
    }
}

Ответы [ 2 ]

8 голосов
/ 04 ноября 2011

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

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

Две большие вещи, которые дает вам использование mocks (и в частности фреймворков для mocking, таких как moq):

1 - Изоляция

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

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

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


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

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

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

3 голосов
/ 04 ноября 2011

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

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

...