Как провести модульное тестирование этого метода (использует буфер обмена и файловую систему)? - PullRequest
0 голосов
/ 03 мая 2018

У меня есть компонент, похожий на проводник, который на самом деле имеет дело с файловой системой. Как начать писать модульные тесты для таких методов, которые требуют использования буфера обмена и фактического перемещения или копирования файлов в файловой системе?

Я пытался просмотреть учебные пособия и онлайн-курсы, но они слишком абстрактны и не могли мне помочь в моем текущем вопросе.

public void DoCtrlV(object obj)
{
    try
    {
        StopWait();
        var list = System.Windows.Clipboard.GetFileDropList();
        if (list.Count > 0) // i.e. from outside - get file list
        {
            if (!PasteFromOutsideSucceeded(list))
                return;
        }
        else // i.e. from inside
        {
            string targetFolder = GetTargetFolder();

            if (Globals.ListInternalUseCopy != null) // from list
            {
                PasteFromList(targetFolder);
            }
            else if (Globals.TreeInternalUseCopy != null) // from tree
            {
                PasteFromTree(targetFolder);
            }
        }

        RefreshBothControls();
    }
    catch (UnauthorizedAccessException ex)
    {
        // doesn't matter atm
    }
}

РЕДАКТИРОВАТЬ / ОБНОВИТЬ : Мне нужно было сделать много вещей, и я все еще в середине, но это то, что я делал до сих пор.

  1. Я извлек весь тестируемый код в отдельный класс, за пределами кода окна, в котором он находился ранее (действительно плохое место для тестирования, так как вам нужно создать экземпляр окна для фактического тестирования). Я передал ему в конструкторе все необходимые объекты для запуска.

Мой DoCtrlV теперь выглядит так:

StopWait();
var list = System.Windows.Clipboard.GetFileDropList();
var result = _hadnler.PerformPaste(Globals.ListInternalUseCopy, Globals.TreeInternalUseCopy, list, MoveNotCopy, shellList.Path, shellTree.SelectedPath);
if (!result)
    MessageBox.Show("Please select a destiantion.");
RefreshBothControls();

И единственное, что я тестирую (атм), это _hadnler.PerformPaste.

  1. Как вы можете видеть, я решил игнорировать буфер обмена и другие факторы прямо сейчас и сосредоточиться только на операциях FileSystem. Моя PerformPaste теперь выглядит так:

    public bool PerformPaste(List<string> listInternalUseCopy, string treeInternalUseCopy, StringCollection clipboardList, bool moveNotCopy, string listPath, string treePath)
    {
        if (clipboardList.Count > 0) // i.e. from outside - get file list
        {
            if (!PasteFromOutsideSucceeded(clipboardList, listPath))
                return false;
        }
        else // i.e. from inside
        {
            string targetFolder = GetTargetFolder(listPath, treePath);
    
            if (listInternalUseCopy != null) // from list
            {
                PasteFromList(targetFolder, moveNotCopy);
            }
            else if (treeInternalUseCopy != null) // from tree
            {
                PasteFromTree(targetFolder, moveNotCopy);
            }
        }
        return true;
    }
    
  2. Мой PerformPaste по-прежнему вызывает под-методы, но теперь они все "ОК". В конце концов, основная проблема заключается в том, что вы получаете File.Move или File.Copy - и поэтому мне нужно что-то для этого. Поэтому я установил пакет NuGet System.IO.Abstractions и изменил свой код для поддержки IFileSystem (в основном заменил все вызовы ввода-вывода, добавив в начале мои новые вызовы объекта IFileSystem). В реальном коде это устанавливается в обычную файловую систему, а в тестовом коде это фиктивная файловая система (также поддерживаемая дочерним пакетом NuGet с именем System.IO.Abstractions.TestingHelpers).

Мой код тестирования теперь выглядит так:

public class MainLogicHandlerTests
{
    private readonly MockFileSystem fileSystem;

    public MainLogicHandlerTests()
    {
        fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
        {
            { @"c:\src\file1.txt", new MockFileData("Test1") },
            { @"c:\src\file2.txt", new MockFileData("Test2") },
            { @"c:\dst\file3.txt", new MockFileData("Test3") }
        });
        FileSystem.UsedFileSystem = fileSystem;
    }

    [TestMethod()]
    public void PasteOneFile_FromOutsideIntoList_ShouldSucceed()
    {
        //Arrange
        List<string> listInternal = new List<string>() { @"c:\src\file1.txt"};
        string treeInternal = null;
        StringCollection clipboardList = new StringCollection();
        clipboardList.Add(@"c:\src\file1.txt");
        bool moveNotCopy = false;
        string listPath = @"c:\dst";
        string treePath = @"c:\dst";

        //Act
        var sut = new MainLogicHandler(null);
        var result = sut.PerformPaste(listInternal, treeInternal, clipboardList, moveNotCopy, listPath, treePath);

        //Assert
        Assert.IsTrue(fileSystem.FileExists(@"c:\dst\file1.txt"));
    }
}

Так что еще долгий путь, но, по крайней мере, это начало. Буду признателен за любые советы, которые у вас есть, ребята ...

1 Ответ

0 голосов
/ 03 мая 2018

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

Например, System.Windows.Clipboard.GetFileDropList находится вне вашего контроля и не должен подвергаться модульному тестированию (это внешняя зависимость). Чтобы не допустить этого в ваш модульный тест, вам нужно использовать внедрение зависимостей.

Создайте интерфейс, подобный этому:

public interface IClipboard
{
    StringCollection GetClipBoardInfo();
}

Внедрить наследующий класс в метод DoCtrlV.

public void DoCtrlV(object obj, IClipboard clipboard)

Создайте класс, который реализует интерфейсную версию метода и возвращает правильную функцию буфера обмена:

public StringCollection GetClipBoardInfo()
{
  System.Windows.Clipboard.GetFileDropList(); 
}

Теперь создайте класс для модульного тестирования, который просто возвращает StringCollection и сообщает вам, был ли вызван метод.

public MockClipboard
{
  public StringCollection GetClipBoardInfo()
  {
    ClipboardWasRead = true;

    StringCollection col = new StringCollection();
    col.Add("...");

    return col;
  }

  public bool ClipboardWasRead { get; set; }
}

Таким образом, вы не занимаетесь модульным тестированием, которое не находится под вашим контролем (например, буфер обмена и файловая система). Если вы хотите проверить, читает ли ваш метод буфер обмена или нет, вы можете проверить его на логическом ClipboardWasRead метода. Здесь действительно важно то, что вам нужно будет переписать свой метод, чтобы он был более тестируемым модулем. Код, который вы сейчас написали, имеет много внешних зависимостей, например:

  • System.Windows.Clipboard.GetFileDropList
  • PasteFromOutsideSucceeded
  • RefreshBothControls

Просто работайте с ними по одному, пока не почувствуете себя комфортно, если ваш код будет тестируемым по вашему вкусу.

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

[TestMethod]
public void WasClipboardRead()
{
  // Arrange
  var mock = new MockClipboard();
  var obj = new Object();

  // Act
  DoCtrlV(obj, mock);

  // Assert
  Assert.IsTrue(mock.ClipboardWasRead);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...