Проблема проектирования модульных тестов C #: Как уменьшить избыточность при написании модульных тестов? - PullRequest
7 голосов
/ 14 октября 2011

Вот моя проблема с модульным тестом c #:

У меня есть один тест, который я хочу запустить на некотором коде, который изменяет файл. Мой тест запустит код, который изменяет файл, а затем проверит результат. Довольно прямолинейно пока ...

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

Я мог бы написать один тест, который запрашивает файлы в папке, а затем запускает тестовую логику для каждого файла, но при использовании этого метода будет сообщаться только один результат прохождения / отказа для всего набора файлов.

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

Есть идеи, как или если это можно сделать в модульном тесте c #? Или с помощью нун-теста?

Спасибо! И я надеюсь, что это не повторяющийся вопрос. Я оглянулся, но ничего не смог найти.

Ответы [ 4 ]

10 голосов
/ 14 октября 2011

Похоже, вам нужен параметризованный тестовый пример: см. http://www.nunit.org/index.php?p=testCaseSource&r=2.5.

Итак:

[TestFixture]
public class Tests
{
    static string[] FileNames = new string[] 
                    { "mary.txt", "mungo.txt", "midge.txt" };

    [Test, TestCaseSource("FileNames")]
    public void TestMethod(string fileName)
    {
        Assert.That(File.Exists(fileName));
    }
}

Атрибут [TestCaseSource] сообщает NUnit получить значениястрокового параметра из строкового массива.

Этот подход, однако, требует статических констант для имен файлов.Если вы предпочитаете использовать программный подход, который читает файлы из базы данных или что-то подобное, попробуйте фабричный класс, например, так:

[TestFixture]
public class Tests
{
    [Test, TestCaseSource(typeof(FilenameFactory), "FileNames")]
    public bool FileCheck(string fileName)
    {
        return File.Exists(fileName);
    }
}

public class FilenameFactory
{
    public static IEnumerable FileNames
    {
        get
        {
            foreach (var filename in 
                   Directory.EnumerateFiles(Environment.CurrentDirectory))
            {
                yield return new TestCaseData(filename).Returns(true);
            }
        }
    }
}

Класс TestCaseData генерирует «тестовые случаи», которые могут иметь ожиданияустановить через свободный интерфейс.

5 голосов
/ 14 октября 2011

Параметризованные тесты (http://www.nunit.org/index.php?p=parameterizedTests&r=2.5) могут быть вам полезны в зависимости от того, как вы их выполняете.

Пример TestcaseAttribute, который вы можете использовать или использовать там.также TestCaseSourceAttribute

[TestCase(12,3,4)]
[TestCase(12,2,6)]
[TestCase(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

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

3 голосов
/ 14 октября 2011

Другой вариант - использовать шаблоны T4 для динамической генерации тестов для вас на основе количества файлов в вашем каталоге. Добавьте этот файл ".tt" в ваш проект модульного тестирования.

Теперь, когда вы делаете сборку, которая должна произойти непосредственно перед нажатием кнопки «Запустить все тесты в решении» в Visual Studio, она должна генерировать модульные тесты для всех файлов в каталоге с именем файла в модульном тесте. Затем ваш тестовый прогон должен иметь хороший список всех файлов, которые он тестировал, и их статусы.

<#@ template debug="false" hostspecific="true" language="C#v3.5" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ output extension=".cs" #>
<#
            string inputDirectory = @"d:\temp";
            var files = System.IO.Directory.GetFiles(inputDirectory);
#>
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        <# foreach (string filePath in files) { #>
        [TestMethod]
        public void TestingFile_<#=System.IO.Path.GetFileNameWithoutExtension(filePath).Replace(' ','_').Replace('-','_')#>()
        {
        File currentFile = System.IO.File.Open(@"<#= filePath #>", FileMode.Open);
        // TODO: Put your standard test code here which will use the file you opened above
        }
        <# } #>
    }
}
0 голосов
/ 14 октября 2011

Прежде всего, тестирование зависит от внешних источников, таких как файлы на диске, не является строго модульным тестированием (мнение).

Вам нужен подход, основанный на данных, и вам следуетищите инструменты, которые его поддерживают, например MSTest или MBunit .(Для получения дополнительной информации перейдите по ссылкам).

Затем вы можете сделать что-то вроде этого (используя MBunit):

[TestFixture]
public class MyTestFixture
{
  [Test]
  public void WordCounter([TextData(ResourcePath = "Data.txt")] string text)
  {
      var wordCounter = new WordCounter(text);
      int count = wordCounter.Count("Firecrest");
      Assert.AreEqual(4, count); // Should not include the plural form "Firecrests".
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...