单元测试采用参数的 WebAPI 控制器
Unit testing WebAPI Controller that takes parameters
我有一个采用如下参数对象的 WebAPI 控制器:
public class InvoicesParameters : QueryStringParameters
{
public string InvoiceType { get; set; } = "P";
public bool Approved { get; set; } = false;
public string Region { get; set; } = null;
public string VendorCode { get; set; } = null;
}
控制器工作正常。我可以传递任何或所有参数并获得预期结果。现在我正在尝试使用 xUnit 为这个控制器添加一个单元测试。我尝试了几种不同的方法,但都失败了。
我的测试是这样的:
[Theory(DisplayName = "Get Invoices")]
[ClassData(typeof(InvoicesParametersTestData))]
public void GetInvoices_ShouldReturnInvoices(InvoicesParameters iparams)
{
var mockService = new Mock<IShopAPService>();
mockService.Setup(x => x.GetInvoices(iparams))
.Returns(GetSampleInvoices());
var controller = new InvoicesController(mockService.Object);
IHttpActionResult actionResult = controller.GetInvoices(iparams);
var contentResult = actionResult as OkNegotiatedContentResult<List<Invoice>>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
Assert.Equal(3, contentResult.Content.Count);
}
private List<InvoiceDto> GetSampleInvoices()
{
List<InvoiceDto> output = new List<InvoiceDto>
{
new InvoiceDto
{
Id = 1,
VendorCode = "PFSATL",
VendorName = "PlantStone LLC",
Type = "I",
PONumber = "54P-00007365",
OrderId = "940817",
InvoiceType = "P",
InvoiceNumber = "DT1010816950",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 2496.48M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
},
new InvoiceDto
{
Id = 2,
VendorCode = "NATSLC",
VendorName = "National American Doodads",
Type = "I",
PONumber = "72P-00004838",
OrderId = "874566",
InvoiceType = "P",
InvoiceNumber = "123454321789",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 457.88M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
},
new InvoiceDto
{
Id = 3,
VendorCode = "BRIDG",
VendorName = "Bridgeport Soda",
Type = "I",
PONumber = "54P-0074865",
OrderId = "741258",
InvoiceType = "P",
InvoiceNumber = "987456",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 74.99M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
}
};
return output;
}
public class InvoicesParametersTestData
{
public static IEnumerable<InvoicesParameters> TestData
{
get
{
yield return new InvoicesParameters { InvoiceType = "P", Approved = false };
yield return new InvoicesParameters { InvoiceType = "P", Approved = true };
}
}
}
这个模式有些不对劲。我收到 ClassData 必须指向有效 class 的编译时错误。有一个更好的方法吗?或者修复我所拥有的东西的方法?
您的 InvoicesParametersTestData
class 应该看起来像这样才能使其正常工作:
public class InvoicesParametersTestData : IEnumerable<object[]>
{
private readonly List<object[]> _testData = new List<object[]>
{
new object[]
{
new InvoicesParameters
{
InvoiceType = "P", Approved = false
},
new InvoicesParameters
{
InvoiceType = "P",
Approved = true
}
}
};
public IEnumerator<object[]> GetEnumerator() => _testData.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
为了能够将 class 与 DataClass 属性一起使用,class 必须继承自 IEnumerable<object[]>
。指定的类型必须是 object
,否则 xUnit 将抛出错误。
因为您正在实施 IEnumerable
,所以您还必须实施 GetEnumerator()
方法。
编辑
错误The test method expected 1 parameter value, but 2 parameter values were provided.
是由_testData
在classInvoicesParametersTestData
中returns 2项造成的。要解决这个问题,您的测试方法应该接受两个参数。喜欢:GetInvoices_ShouldReturnInvoices(InvoicesParameters iparams, InvoicesParameters iparams2)
.
但是,这会导致一个奇怪的测试。
更好的设置方法是使用 InlineData
属性:
[Theory(DisplayName = "Get Invoices")]
[InlineData(true)]
[InlineData(false)]
public void GetInvoices_ShouldReturnInvoices(bool approved)
{
var iparams = new InvoicesParameters
{
InvoiceType = "P",
Approved = approved
};
var mockService = new Mock<IShopAPService>();
mockService.Setup(x => x.GetInvoices(iparams))
.Returns(GetSampleInvoices());
var controller = new InvoicesController(mockService.Object);
IHttpActionResult actionResult = controller.GetInvoices(iparams);
var contentResult = actionResult as OkNegotiatedContentResult<List<Invoice>>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
Assert.Equal(3, contentResult.Content.Count);
}
您将不再需要 InvoicesParametersTestData
class。
如果您也想创建 InvoiceType 变量,您可以这样做:
[InlineData(true, "P")]
[InlineData(false, "X")]
public void GetInvoices_ShouldReturnInvoices(bool approved, string invoiceType)
我有一个采用如下参数对象的 WebAPI 控制器:
public class InvoicesParameters : QueryStringParameters
{
public string InvoiceType { get; set; } = "P";
public bool Approved { get; set; } = false;
public string Region { get; set; } = null;
public string VendorCode { get; set; } = null;
}
控制器工作正常。我可以传递任何或所有参数并获得预期结果。现在我正在尝试使用 xUnit 为这个控制器添加一个单元测试。我尝试了几种不同的方法,但都失败了。
我的测试是这样的:
[Theory(DisplayName = "Get Invoices")]
[ClassData(typeof(InvoicesParametersTestData))]
public void GetInvoices_ShouldReturnInvoices(InvoicesParameters iparams)
{
var mockService = new Mock<IShopAPService>();
mockService.Setup(x => x.GetInvoices(iparams))
.Returns(GetSampleInvoices());
var controller = new InvoicesController(mockService.Object);
IHttpActionResult actionResult = controller.GetInvoices(iparams);
var contentResult = actionResult as OkNegotiatedContentResult<List<Invoice>>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
Assert.Equal(3, contentResult.Content.Count);
}
private List<InvoiceDto> GetSampleInvoices()
{
List<InvoiceDto> output = new List<InvoiceDto>
{
new InvoiceDto
{
Id = 1,
VendorCode = "PFSATL",
VendorName = "PlantStone LLC",
Type = "I",
PONumber = "54P-00007365",
OrderId = "940817",
InvoiceType = "P",
InvoiceNumber = "DT1010816950",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 2496.48M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
},
new InvoiceDto
{
Id = 2,
VendorCode = "NATSLC",
VendorName = "National American Doodads",
Type = "I",
PONumber = "72P-00004838",
OrderId = "874566",
InvoiceType = "P",
InvoiceNumber = "123454321789",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 457.88M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
},
new InvoiceDto
{
Id = 3,
VendorCode = "BRIDG",
VendorName = "Bridgeport Soda",
Type = "I",
PONumber = "54P-0074865",
OrderId = "741258",
InvoiceType = "P",
InvoiceNumber = "987456",
InvoiceDate = Convert.ToDateTime("01/01/2020"),
InvoiceAmount = 74.99M,
Region = "WEST",
ShopNumber = "16",
ApprovalDate = null,
Approver = null
}
};
return output;
}
public class InvoicesParametersTestData
{
public static IEnumerable<InvoicesParameters> TestData
{
get
{
yield return new InvoicesParameters { InvoiceType = "P", Approved = false };
yield return new InvoicesParameters { InvoiceType = "P", Approved = true };
}
}
}
这个模式有些不对劲。我收到 ClassData 必须指向有效 class 的编译时错误。有一个更好的方法吗?或者修复我所拥有的东西的方法?
您的 InvoicesParametersTestData
class 应该看起来像这样才能使其正常工作:
public class InvoicesParametersTestData : IEnumerable<object[]>
{
private readonly List<object[]> _testData = new List<object[]>
{
new object[]
{
new InvoicesParameters
{
InvoiceType = "P", Approved = false
},
new InvoicesParameters
{
InvoiceType = "P",
Approved = true
}
}
};
public IEnumerator<object[]> GetEnumerator() => _testData.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
为了能够将 class 与 DataClass 属性一起使用,class 必须继承自 IEnumerable<object[]>
。指定的类型必须是 object
,否则 xUnit 将抛出错误。
因为您正在实施 IEnumerable
,所以您还必须实施 GetEnumerator()
方法。
编辑
错误The test method expected 1 parameter value, but 2 parameter values were provided.
是由_testData
在classInvoicesParametersTestData
中returns 2项造成的。要解决这个问题,您的测试方法应该接受两个参数。喜欢:GetInvoices_ShouldReturnInvoices(InvoicesParameters iparams, InvoicesParameters iparams2)
.
但是,这会导致一个奇怪的测试。
更好的设置方法是使用 InlineData
属性:
[Theory(DisplayName = "Get Invoices")]
[InlineData(true)]
[InlineData(false)]
public void GetInvoices_ShouldReturnInvoices(bool approved)
{
var iparams = new InvoicesParameters
{
InvoiceType = "P",
Approved = approved
};
var mockService = new Mock<IShopAPService>();
mockService.Setup(x => x.GetInvoices(iparams))
.Returns(GetSampleInvoices());
var controller = new InvoicesController(mockService.Object);
IHttpActionResult actionResult = controller.GetInvoices(iparams);
var contentResult = actionResult as OkNegotiatedContentResult<List<Invoice>>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
Assert.Equal(3, contentResult.Content.Count);
}
您将不再需要 InvoicesParametersTestData
class。
如果您也想创建 InvoiceType 变量,您可以这样做:
[InlineData(true, "P")]
[InlineData(false, "X")]
public void GetInvoices_ShouldReturnInvoices(bool approved, string invoiceType)