[C#]Supplying Test Data from External Methods with MemberData in xUnit.net

目次

Overview

This implementation uses the [MemberData] attribute in xUnit.net to dynamically supply parameters to test methods from static methods or properties. It is suitable for managing “arrays,” “objects,” “dynamically generated data,” and “large sets of test cases” that are difficult to handle with [InlineData].

Specifications (Input/Output)

  • Data Source: Create a public static method that returns IEnumerable<object[]>.
  • Test Method: Use the [MemberData] attribute to specify the name of the source method and receive the data through arguments.
  • Behavior: The test method is executed repeatedly for the number of data entries supplied.

Basic Usage

// Data supply method
public static IEnumerable<object[]> GetNames()
{
    // { Expected value, Input 1, Input 2 }
    yield return new object[] { "John Doe", "John", "Doe" };
    yield return new object[] { "Jane Smith", "Jane", "Smith" };
}

[Theory]
[MemberData(nameof(GetNames))]
public void NameTest(string expected, string first, string last)
{
    // ...
}

Full Code

This code verifies multiple name patterns for a method that combines a first name and a last name to generate a full name.

using System;
using System.Collections.Generic;
using Xunit;

namespace ParameterizedTests
{
    public class MemberDataSample
    {
        /// <summary>
        /// Static method providing test data.
        /// The return type must be IEnumerable<object[]>.
        /// </summary>
        public static IEnumerable<object[]> NameData()
        {
            // The contents of the object array are mapped to the test method arguments (expected, first, last)
            yield return new object[] { "Taro Yamada", "Taro", "Yamada" };
            yield return new object[] { "John Doe", "John", "Doe" };
            yield return new object[] { "Tech User", "Tech", "User" };
        }

        /// <summary>
        /// Executes the test using data obtained from the method specified in MemberData
        /// </summary>
        [Theory]
        [MemberData(nameof(NameData))]
        public void GetFullName_ReturnsCombinedString(string expected, string first, string last)
        {
            // Arrange
            var generator = new NameGenerator();

            // Act
            var result = generator.GetFullName(first, last);

            // Assert
            Assert.Equal(expected, result);
        }
    }

    /// <summary>
    /// Class to be tested
    /// </summary>
    public class NameGenerator
    {
        public string GetFullName(string firstName, string lastName)
        {
            return $"{firstName} {lastName}";
        }
    }
}

Customization Points

  • Using Properties: You can specify static properties as a data source instead of methods.C#public static TheoryData<string, string, string> TestCases => new TheoryData<string, string, string> { { "A B", "A", "B" }, { "X Y", "X", "Y" } }; Using the TheoryData class allows you to define data in a type-safe manner.
  • Using External Classes: If you want to separate test data definitions into a different class, use the MemberType property. [MemberData(nameof(ExternalData.GetData), MemberType = typeof(ExternalData))]

Points of Caution

  • Must be Static: Methods or properties that provide data must be static.
  • Match Type and Order: The “type” and “order” of data described in new object[] { ... } must exactly match the argument definitions of the test method. Mismatches will cause type conversion errors at runtime.
  • Visibility: Data provider members generally need to be public.

Application

Dynamic Generation with Parameterized MemberData

This example shows how to pass parameters to the data generation method itself to control the number or range of test data.

public static IEnumerable<object[]> GetRange(int count)
{
    for (int i = 1; i <= count; i++)
    {
        yield return new object[] { i };
    }
}

// Generate 5 pieces of data and test
[Theory]
[MemberData(nameof(GetRange), parameters: 5)]
public void CheckPositiveNumbers(int number)
{
    Assert.True(number > 0);
}

Summary

Using [MemberData] allows you to separate test logic (the [Theory] method) from test data (the static method). This makes it easier to add or change data and maintains high readability in your test code, especially when verifying complex objects or a large number of patterns.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次