เราจะรันวิธีทดสอบด้วยพารามิเตอร์หลายตัวใน MSTest ได้อย่างไร


140

NUnit มีคุณสมบัติที่เรียกว่าค่าเช่นด้านล่าง:

[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คำตอบ
Michael Freidgeim

เป็นไปได้ที่ซ้ำกันของวิธีการ RowTest กับ MSTest
Michael Freidgeim

@MichaelFreidgeim คำถามนี้มีคำตอบที่ดีกว่าเป้าหมายที่คุณแนะนำ
Rob

1
@Rob: IMHO คำตอบที่เหมาะสมที่สุด -MSTestHacks - วิธี RowTest ด้วย MSTest? ไม่มีในคำถามนี้
Michael Freidgeim

@MichaelFreidgeim บางทีถึงแม้ว่าฟังก์ชั่นนี้จะมีอยู่เป็นเวลา 3 1/2 ปีแล้ว ( stackoverflow.com/questions/9021881/ … )
Rob

คำตอบ:


46

ขออภัยที่ไม่รองรับ MSTest รุ่นเก่า เห็นได้ชัดว่ามีรูปแบบการขยายและคุณสามารถใช้มันด้วยตัวคุณเอง อีกตัวเลือกหนึ่งที่จะใช้การทดสอบที่ขับเคลื่อนด้วยข้อมูล

ความคิดเห็นส่วนตัวของฉันจะแค่ติดกับ NUnit แม้ว่า ...

ตั้งแต่ Visual Studio 2012 อัพเดต 1 MSTest มีคุณสมบัติที่คล้ายกัน ดู คำตอบของ McAden


เรากำลังใช้ซีลีเนียมซึ่งจะสร้างรหัส NUnit ดังนั้นเราจึงเปลี่ยนไปใช้ NUnit แทน :)
The Light

4
ฉันพบว่าสิ่งที่คล้ายกันตอนนี้เป็นไปได้ใน Visual Studio 2012 Update 1 เพียง FYI สำหรับการพิจารณาในอนาคตของใครก็ตามที่ดูคำตอบนี้
McAden

@ McAden คุณมีลิงค์พร้อมคำอธิบายหรือไม่?
jeroenh

6
ฉันให้คำตอบด้านล่างพร้อมตัวอย่างและลิงค์ไปยังโพสต์บล็อกของฉัน มันกล่าวถึงคุณลักษณะที่จำเป็นและคุณสมบัติ "DisplayName" ในแอตทริบิวต์ที่แยกกรณีและปัญหาใน Test Explorer มันถูกกล่าวถึงในการประกาศ CTP เดือนตุลาคม (ซึ่งตอนนี้มีการเปิดตัวอย่างเป็นทางการ) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/ …ฉันได้เพิ่มข้อมูลลงในคำถาม SO นี้เพราะฉัน ใช้เวลาสักครู่เพื่อค้นหามัน หวังว่านี่จะช่วยใครซักคนในบางเวลา
McAden

167

แก้ไข 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 WinRTคนเกียจคร้าน

แก้ไข 2 : ข้อมูลต่อไปนี้เป็นข้อมูลเมตาที่พบโดยใช้ "Go To Definition" ภายใน 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 : ปัญหานี้เกิดขึ้นในฟอรัม UserVoice ของ Visual Studio สถานะการอัพเดทล่าสุด:

เริ่มต้นแล้ว·ทีม Visual Studio ADMIN ทีม Visual Studio (ทีมผลิตภัณฑ์, Microsoft Visual Studio) ตอบกลับ· 25 เมษายน 2016 ขอบคุณสำหรับความคิดเห็น เราเริ่มทำสิ่งนี้แล้ว

Pratap Lakshman Visual Studio

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


4
ขณะนี้รองรับ Windows Phone ด้วยด้วย Visual Studio 2012 Update 2 (ปัจจุบัน CTP 4)
Pedro Lamas

8
ฉันมีการอัพเดต 1 แต่ DataTestMethod และ DataRow ไม่ได้รับการยอมรับซึ่งเป็นคุณลักษณะของไลบรารีใดบ้าง
DevDave

3
มีแหล่งข้อมูลอย่างเป็นทางการเกี่ยวกับ DataTestMethod หรือไม่ มีเนมสเปซอะไรอยู่ในนั้น
Igor Lankin

2
ฉันพบว่า UnitTestFramework.dll ได้รับการติดตั้งบนคอมพิวเตอร์ของฉันและหลังจากการอ้างอิงด้วยตนเองฉันสามารถเขียนวิธีการโดยใช้แอตทริบิวต์ [DataTestMethod] พร้อมแถวข้อมูล แต่ฉันไม่ได้รับ Test Explorer ใน Visual Studio 2012.3 เพื่อค้นหาวิธี
Josh DeLong

5
ฉันไปที่เส้นทางไฟล์ "C: \ Program Files (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" บนคอมพิวเตอร์ของฉัน และไฟล์อยู่ที่นั่น ดังนั้นฉันจึงอ้างอิงในโครงการทดสอบหน่วยพื้นฐานของฉัน การเปิด dll ใน JustDecompile แสดงว่าไลบรารีมีการอ้างอิงถึง mscorlib, System, และ System.Core เท่านั้น มันไม่ใช่โครงการ Windows Store
Josh DeLong

34

ฟีเจอร์นี้เปิดตัวล่วงหน้าและสามารถใช้งานได้กับ 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);
    }
}

นี่คือคำตอบที่ถูกต้อง โปรดทราบว่าไม่จำเป็นต้องพูดว่า [DataTestMethod] เพื่อใช้ [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar

11

ไม่เหมือนกับแอตทริบิวต์Value(หรือTestCase) ของ NUnit ทุกประการ แต่ MSTest มีDataSourceแอตทริบิวต์ซึ่งให้คุณทำสิ่งที่คล้ายกันได้

คุณสามารถขอได้ถึงฐานข้อมูลหรือไฟล์ XML - ไม่ตรงไปตรงมาเป็นคุณลักษณะของ NUnit แต่ทำงานได้


7

MSTest มีแอตทริบิวต์ประสิทธิภาพที่เรียกว่าแหล่งข้อมูล การใช้สิ่งนี้คุณสามารถทำการทดสอบที่ขับเคลื่อนด้วยข้อมูลตามที่คุณถาม คุณสามารถมีข้อมูลการทดสอบของคุณใน 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") แยกวิเคราะห์และจัดการในเนื้อหาของการทดสอบ
Andrey Burykin

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 DataRowAttributeVisual 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
คุณควรแบ่งการทดสอบแต่ละครั้งเป็นการทดสอบแยกต่างหากเพื่อประหยัดเวลาเมื่อหนึ่งในนั้นจะหยุด (ซึ่งเราทุกคนรู้ว่าจะเกิดขึ้น)
เงิน

ใช่แน่นอน ในทางปฏิบัตินั่นเป็นวิธีที่จะทำ ในกรณีนี้ฉันแค่อธิบายเพื่อความเรียบง่าย
Brandon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.