Как мы можем запустить тестовый метод с несколькими параметрами в MSTest?

147

В NUnit есть функция под названием Values, как показано ниже:

[Test]
public void MyTest(
    [Values(1,2,3)] int x,
    [Values("A","B")] string s)
{
    // ...
}

Это означает, что метод тестирования будет выполнен шесть раз:

MyTest(1, "A")
MyTest(1, "B")
MyTest(2, "A")
MyTest(2, "B")
MyTest(3, "A")
MyTest(3, "B")

Сейчас мы используем MSTest, но есть ли для него эквивалент, чтобы я мог запустить один и тот же тест с несколькими параметрами?

[TestMethod]
public void Mytest()
{
    // ...
}
Свет
источник
Вы можете использовать MSTestHacks, как описано в ответе stackoverflow.com/a/19536942/52277 .
Майкл Фрейджейм
Возможный дубликат How to RowTest with MSTest?
Майкл Фрейджейм
@MichaelFreidgeim На этот вопрос есть ответы лучше, чем ваша предполагаемая цель
Роб
1
@Rob: IMHO, наиболее подходящий ответ -MSTestHacks - Как выполнить RowTest с MSTest? отсутствует в этом вопросе.
Майкл Фрейджейм
@MichaelFreidgeim Возможно, хотя кажется, что функциональность существует уже 3,5 года ( stackoverflow.com/questions/9021881/… )
Роб

Ответы:

46

К сожалению, он не поддерживается в более старых версиях MSTest. Судя по всему, есть модель расширяемости и ее можно реализовать самостоятельно . Другой вариант - использовать тесты на основе данных .

Мое личное мнение было бы просто придерживаться NUnit ...

Начиная с Visual Studio 2012, обновление 1, MSTest имеет аналогичную функцию. См . Ответ Макадена .

Джерун
источник
Мы используем Selenium, который генерирует код NUnit, поэтому мы перешли на использование NUnit :)
The Light
4
Я обнаружил, что нечто подобное теперь возможно в Visual Studio 2012 с обновлением 1, просто к вашему сведению для будущего рассмотрения всех, кто смотрит этот ответ.
McAden
@McAden у вас есть ссылка с объяснением?
jeroenh
6
Я дал ответ ниже с примером и ссылкой на мой пост в блоге. В нем упоминаются необходимые атрибуты, а также свойство «DisplayName» атрибута, который различает случаи в обозревателе тестов. Об этом также упоминалось в октябрьском объявлении CTP (который теперь имеет официальный выпуск) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/ ... Я добавил информацию к этому вопросу SO, потому что я потратил довольно много времени на его поиски. Надеюсь, это кому-то сэкономит время.
McAden
171

РЕДАКТИРОВАТЬ 4 : Похоже, это завершено в MSTest V2 17 июня 2016 г .: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Оригинальный ответ :

Примерно неделю назад в Visual Studio 2012 Update 1 теперь возможно нечто подобное:

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

РЕДАКТИРОВАТЬ : Похоже, это доступно только в проекте модульного тестирования для WinRT / Metro . Облом

РЕДАКТИРОВАТЬ 2 : Следующие метаданные можно найти с помощью «Перейти к определению» в Visual Studio:

#region Assembly Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll, v11.0.0.0
// C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll
#endregion

using System;

namespace Microsoft.VisualStudio.TestPlatform.UnitTestFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodAttribute : TestMethodAttribute
    {
        public DataTestMethodAttribute();

        public override TestResult[] Execute(ITestMethod testMethod);
    }
}

РЕДАКТИРОВАТЬ 3 : эта проблема была поднята на форумах Visual Studio UserVoice. Последнее обновление гласит:

НАЧАЛОСЯ · Команда Visual Studio ADMIN Команда Visual Studio (группа разработки продукта, Microsoft Visual Studio) ответила · 25 апреля 2016 г. Благодарим вас за отзыв. Мы начали над этим работать.

Пратап Лакшман Visual Studio

https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit

McAden
источник
4
Windows Phone теперь также поддерживается с обновлением Visual Studio 2012 Update 2 (в настоящее время CTP 4)
Педро Ламас,
8
У меня есть обновление 1, но DataTestMethod и DataRow не распознаются. В какой библиотеке находятся эти атрибуты?
DevDave
3
Есть ли официальный источник о DataTestMethod? В каком пространстве имен он находится, в какой сборке?
Игорь Ланкин
2
Я обнаружил, что UnitTestFramework.dll был установлен на моем компьютере, и после ручного обращения к нему я смог написать метод, используя атрибут [DataTestMethod] со строками данных, но я не могу заставить Test Explorer в Visual Studio 2012.3 найти метод.
Джош Делонг,
5
Я перешел по пути к файлу "C: \ Program Files (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ нейтральный \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" на моем компьютере и файл был там. Поэтому я сослался на него в своем основном проекте модульного тестирования. Открытие dll в JustDecompile показывает, что в библиотеке есть ссылки только на mscorlib, System и System.Core. Это не проект Магазина Windows.
Джош Делонг,
36

Эта функция сейчас находится в предварительной версии и работает с Visual Studio 2015.

Например:

[TestClass]
public class UnitTest1
{
    [DataTestMethod]
    [DataRow(1, 2, 2)]
    [DataRow(2, 3, 5)]
    [DataRow(3, 5, 8)]
    public void AdditionTest(int a, int b, int result)
    {
        Assert.AreEqual(result, a + b);
    }
}
Помпа
источник
1
Это правильный ответ. Обратите внимание, что для использования [DataRow] необязательно указывать [DataTestMethod] ( stackoverflow.com/a/59162403/2540235 )
mattavatar
11

Не то же самое, что атрибуты Value(или TestCase) NUnit , но у MSTest есть DataSourceатрибут, который позволяет вам делать то же самое.

Вы можете подключить его к базе данных или XML-файлу - это не так просто, как функция NUnit, но она выполняет свою работу.

км
источник
7

MSTest имеет мощный атрибут под названием DataSource . Используя это, вы можете выполнять тесты на основе данных по вашему запросу. Вы можете иметь свои тестовые данные в XML, CSV или в базе данных. Вот несколько ссылок, которые помогут вам

Притам Кармакар
источник
6

Реализовать это очень просто - нужно использовать TestContextсвойство и TestPropertyAttribute.

пример

public TestContext TestContext { get; set; }
private List<string> GetProperties()
{
    return TestContext.Properties
        .Cast<KeyValuePair<string, object>>()
        .Where(_ => _.Key.StartsWith("par"))
        .Select(_ => _.Value as string)
        .ToList();
}

//usage
[TestMethod]
[TestProperty("par1", "http://getbootstrap.com/components/")]
[TestProperty("par2", "http://www.wsj.com/europe")]
public void SomeTest()
{
    var pars = GetProperties();
    //...
}

РЕДАКТИРОВАТЬ:

Я подготовил несколько методов расширения, чтобы упростить доступ к TestContextсвойству и действовать так, как будто у нас есть несколько тестовых примеров. См. Пример обработки простых тестовых свойств здесь:

[TestMethod]
[TestProperty("fileName1", @".\test_file1")]
[TestProperty("fileName2", @".\test_file2")]
[TestProperty("fileName3", @".\test_file3")]
public void TestMethod3()
{
    TestContext.GetMany<string>("fileName").ForEach(fileName =>
    {
        //Arrange
        var f = new FileInfo(fileName);

        //Act
        var isExists = f.Exists;

        //Asssert
        Assert.IsFalse(isExists);
    });
}

и пример с созданием сложных тестовых объектов:

[TestMethod]
//Case 1
[TestProperty(nameof(FileDescriptor.FileVersionId), "673C9C2D-A29E-4ACC-90D4-67C52FBA84E4")]
//...
public void TestMethod2()
{
    //Arrange
    TestContext.For<FileDescriptor>().Fill(fi => fi.FileVersionId).Fill(fi => fi.Extension).Fill(fi => fi.Name).Fill(fi => fi.CreatedOn, new CultureInfo("en-US", false)).Fill(fi => fi.AccessPolicy)
        .ForEach(fileInfo =>
        {
            //Act
            var fileInfoString = fileInfo.ToString();

            //Assert
            Assert.AreEqual($"Id: {fileInfo.FileVersionId}; Ext: {fileInfo.Extension}; Name: {fileInfo.Name}; Created: {fileInfo.CreatedOn}; AccessPolicy: {fileInfo.AccessPolicy};", fileInfoString);
        });
}

Ознакомьтесь с методами расширения и набором примеров для получения более подробной информации.

Андрей Бурыкин
источник
2
Этот подход работает, но не создает отдельных тестовых примеров для каждого набора параметров.
usr4896260
Вы можете использовать что-то более сложное в качестве значения TestProperty (например, «0-100»), анализировать и обрабатывать его в теле теста.
Андрей Бурыкин
4

Есть, конечно, другой способ сделать это, который не обсуждался в этом потоке, то есть путем наследования класса, содержащего TestMethod. В следующем примере определен только один TestMethod, но выполнено два тестовых случая.

В Visual Studio 2012 он создает два теста в TestExplorer:

  1. DemoTest_B10_A5.test
  2. DemoTest_A12_B4.test

    public class Demo
    {
        int a, b;
    
        public Demo(int _a, int _b)
        {
            this.a = _a;
            this.b = _b;
        }
    
        public int Sum()
        {
            return this.a + this.b;
        }
    }
    
    public abstract class DemoTestBase
    {
        Demo objUnderTest;
        int expectedSum;
    
        public DemoTestBase(int _a, int _b, int _expectedSum)
        {
            objUnderTest = new Demo(_a, _b);
            this.expectedSum = _expectedSum;
        }
    
        [TestMethod]
        public void test()
        {
            Assert.AreEqual(this.expectedSum, this.objUnderTest.Sum());
        }
    }
    
    [TestClass]
    public class DemoTest_A12_B4 : DemoTestBase
    {
        public DemoTest_A12_B4() : base(12, 4, 16) { }
    }
    
    public abstract class DemoTest_B10_Base : DemoTestBase
    {
        public DemoTest_B10_Base(int _a) : base(_a, 10, _a + 10) { }
    }
    
    [TestClass]
    public class DemoTest_B10_A5 : DemoTest_B10_Base
    {
        public DemoTest_B10_A5() : base(5) { }
    }
    
Сумья Датта
источник
3

Я не мог заставить The DataRowAttributeработать в Visual Studio 2015, и вот что у меня получилось:

[TestClass]
public class Tests
{
    private Foo _toTest;

    [TestInitialize]
    public void Setup()
    {
        this._toTest = new Foo();
    }

    [TestMethod]
    public void ATest()
    {
        this.Perform_ATest(1, 1, 2);
        this.Setup();

        this.Perform_ATest(100, 200, 300);
        this.Setup();

        this.Perform_ATest(817001, 212, 817213);
        this.Setup();
    }

    private void Perform_ATest(int a, int b, int expected)
    {
        // Obviously this would be way more complex...

        Assert.IsTrue(this._toTest.Add(a,b) == expected);
    }
}

public class Foo
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

Настоящее решение здесь - просто использовать NUnit (если вы не застряли в MSTest, как я в этом конкретном случае).

Брэндон
источник
3
вы должны разделить каждый тестовый вызов на отдельный тест, чтобы сэкономить время, когда один из них сломается. (что, как мы все знаем, произойдет)
серебро
Да, конечно. На практике так и будет. В данном случае я просто проиллюстрировал это для простоты
Брэндон