user5032790
user5032790

Reputation:

Use class in the test's inlineData

I have used the following class as my Mocked class:

public class MockData
{
    public static MockData Current { get; } = new MockData();
    public List<ClientViewModel> Choices { get; set; }

    public MockData()
    {
        Choices = new List<ClientViewModel>
        {
            new ClientViewModel { Answers = new[] { false, false, false } },
            new ClientViewModel { Answers = new[] { true, true, true } },
            new ClientViewModel { Answers = new[] { true, true, false } },
            new ClientViewModel { Answers = new[] { true, false, true } },
            new ClientViewModel { Answers = new[] { true, false, false } }
        };
    }
}

Now I am trying to test the above user choices to see if each instance of ClientViewModel class give me the expected string answer. To achieve this I have used the following test method:

[Fact]
public void ClientRequest_UserChoicesPassed_ReturnsRightAnswer()
{
    // Arrange
    var clientViewModel = MockData.Current.Choices[0];

    // Act
    var jsonResult = _controller.ClientRequest(clientViewModel) as JsonResult;

    // Assert
    string expectedAnswer = "It is a book";
    Assert.Equal(expectedAnswer, ((ResultDTO)jsonResult.Value).Result);
}

This works perfectly and my test is passed as expected. However my problem with this approach is that I have to repeat this test for other entries as well, as you noticed I have used var clientViewModel = MockData.Current.Choices[0]; in the Arrange section of the test, to test the first entry, I don't want to repeat myself by writing multiple tests for this purpose. I already aware of [Theory] and [InlineData] concepts in xNunit, however, it seems I have some difficulty with class, please see below:

[Theory]
[InlineData(MockData.Current.Choices[0], "It is a book")]
[InlineData(MockData.Current.Choices[1], "It is a pen")]
public void ClientRequest_UserChoicesPassed_ReturnsRightAnswer(ClientViewModel clientViewModel, string expectedAnswer)
{
  //...
}

But this gives me the following exception:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

So please let me know, is there any way, I can do anything to prevent repeating this method?

Upvotes: 3

Views: 3743

Answers (1)

Jonathon Chase
Jonathon Chase

Reputation: 9704

To accomplish this, you can use the MemberDataAttribute with a public static method that returns your test cases to be used. Here's an example:

public static IEnumerable<object[]> GetUserChoiceTestData() 
{
    yield return new object[] { MockData.Current.Choices[0], "It is a book" };
    yield return new object[] { MockData.Current.Choices[1], "It is a pen" };
}

Which, you would then apply to your test theory like so:

[Theory]
[MemberData(nameof(GetUserChoiceTestData))]
public void ClientRequest_UserChoicesPassed_ReturnsRightAnswer(ClientViewModel clientViewModel, string expectedAnswer)
{
  //...
}

This will work so long as the static method is a member of the test class you are running. If it's a member of another non-static class, you'll need to additionally provide that type to the MemberDataAttribute.

[MemberData(nameof(SomeOtherClass.GetUserChoiceTestData), MemberType = typeof(SomeOtherClass))]

Upvotes: 8

Related Questions