Reputation: 1962
I am trying to convert 4 almost identical testcases into one, where the one instead uses xUnits InlineData.
The thing is that the parameter, which I want to differ is a long string - actually a JSON-"string" with small changes. It goes like this (I've only taken the relevant):
....
....
var mockHttp = new Mock<HttpMessageHandler>(MockBehavior.Strict);
mockHttp
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent( // the below part is the only thing that differs
"{'content':[" +
"{'Id':'00001', 'eNumber':'001', 'isOwner': true, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"]}"
)
})
.Verifiable();
var httpClient = new HttpClient(mockHttp.Object)
{
BaseAddress = new Uri("http://something.com/")
};
The next test contains the same, but with another 'content', that goes like this:
....
....
"{'content':[" +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'002', 'isOwner': false, 'isAlone':true}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"]}"
....
....
and a third goes like this:
....
....
"{'content':[" +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':false}," +
"{'Id':'00001', 'eNumber':'no', 'isOwner': false, 'isAlone':true}," +
"{'Id':'00001', 'eNumber':'007', 'isOwner': true, 'isAlone':true}," +
"{'Id':'00001', 'eNumber':'003', 'isOwner': false, 'isAlone':false}," +
"]}"
....
....
and so forth with the two next. So I am wondering if there is a smart way to put the 5 types of contents inside a InlineData as a parameter - and thereby somehow save a lot of copied code? There probably is, but I still havent figured out how, without actually writing a lot of code anyway.
Writing the tests as 5 individual tests all goes green, so the only thing I am looking for is a smarter way to write the code, making it cleaner and easier to read, by only changing the parameter/string inside StringContent.
Update as per question in comments:
The class I am testing goes something like this:
....
....
var httpResponseMessage = await User(// something);
if (!httpResponseMessage .IsSuccessStatusCode) return;
var content = await httpResponseMessage.Content.ReadAsStringAsync();
var deserializedContent = JsonConvert.DeserializeObject<UserModel>(content); // it fails here...
....
....
my UserModel class looks like this:
public class UserModel
{
public UserModelDto[] {get; set;}
}
and my UserModelDto class looks like this:
public class UserModelDto
{
public string Id{ get; set; }
public string ENumber { get; set; }
public bool IsOwner { get; set; }
public bool IsAlone { get; set; }
}
Upvotes: 0
Views: 1266
Reputation: 735
FYI for those who come across this question in google when searching for Xunit inlinedata for a long variable.
this was giving errors. [InlineData(0)]
this is the solution [InlineData((long)0)] where 0 is my input variable.
Upvotes: 0
Reputation: 2681
Extending on my comment and providing an answer, you can use MemberDataAttribute
or ClassDataAttribute
to achieve this. This example uses MemberDataAttribute
.
First create a class to represent your model.
public class UserModel
{
[JsonProperty("content")]
public UserModelDto[] {get; set;}
}
public class UserModelDto
{
[JsonProperty("id")]
public string Id{ get; set; }
[JsonProperty("eNumber")]
public string ENumber { get; set; }
[JsonProperty("isOwner")]
public bool IsOwner { get; set; }
[JsonProperty("isAlone")]
public bool IsAlone { get; set; }
}
Add a public static IEnumerable<object[]>
property, or method, to your test class, which also contains your test scenarios.
public static IEnumerable<object[]> TestCaseScenarios
=> new object[][]
{
new object[]
{
new UserModel
{
Contents = new[]
{
new UserModelDto
{
Id = "00001",
ENumber = "no",
IsOwner = false,
IsAlone = false
},
new UserModelDto
{
Id = "00001",
ENumber = "007",
IsOwner = true,
IsAlone = true
},
}
}
},
new object[] { } //etc
}
Apply the MemberDataAttribute
to your test
[Theory] // Tests which accept parameters require the TheoryAttribute, instead of FactAttribute
[MemberData(nameof(TestCaseScenarios))]
public async Task PerformingAction_WithCriteria_ReturnsExpectedThing(UserModel userModel)
{
// Serialize userModelto create a string
var userModelAsString = JsonConvert.SerializeObject(userModel);
// Create the StringContent object
var stringContent = new StringContent(userModelAsString);
// Create a HttpClient whose BaseAddress is the host address
var mockHttp = new Mock<HttpMessageHandler>(MockBehavior.Strict);
mockHttp
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(stringContent)
})
.Verifiable();
var httpClient = new HttpClient(mockHttp.Object) { BaseAddress = new Uri("http://something.com") };
}
Upvotes: 2