使用 NSubstitute 将 Arg.Any<int>() 作为参数传递时出现 NullReferenceException
NullReferenceException when passing Arg.Any<int>() as argument using NSubstitute
我有一个客户 class,它接受 IDbGateway 接口作为构造函数参数。我需要使用 NUnit 和 NSubstitute 为 class 编写单元测试 CalculateWage_HourlyPayed_ReturnsCorrectWage。当我通过 anyId 时,我的单元测试工作正常。但我想传递 Arg.Any<int>()
而不是 anyId。目前我的测试失败了,因为 decimal actual = sut.CalculateWage(Arg.Any<int>());
给出了 NullReferenceException
。为什么我的代码适用于 anyId 值传递但不适用于 Arg.Any<int>()
?
目标成员如下
public class Customer
{
private readonly IDbGateway _gateway;
public Customer(IDbGateway gateway)
{
_gateway = gateway;
}
public decimal CalculateWage(int id)
{
WorkingStatistics ws = _gateway.GetWorkingStatistics(id);
decimal wage;
if (ws.PayHourly)
{
wage = ws.WorkingHours * ws.HourSalary;
}
else
{
wage = ws.MonthSalary;
}
return wage;
}
}
public interface IDbGateway
{
WorkingStatistics GetWorkingStatistics(int id);
}
public class DbGateway : IDbGateway
{
public WorkingStatistics GetWorkingStatistics(int id)
{
throw new NotImplementedException();
}
}
public class WorkingStatistics
{
public decimal HourSalary { get; set; }
public int WorkingHours { get; set; }
public decimal MonthSalary { get; set; }
public bool PayHourly { get; set; }
}
这是有问题的测试
[TestFixture]
public class CustomerTestsWithNSubstitute
{
[Test]
public void CalculateWage_HourlyPayed_ReturnsCorrectWage()
{
var gateway = Substitute.For<IDbGateway>();
var workingStatistics = new Business.Demo.WorkingStatistics()
{ PayHourly = true, HourSalary = 100, WorkingHours = 10 };
const int anyId = 1;
//gateway.GetWorkingStatistics(anyId).ReturnsForAnyArgs(workingStatistics);
gateway.GetWorkingStatistics(Arg.Any<int>()).ReturnsForAnyArgs(workingStatistics);
const decimal expectedWage = 100 * 10;
var sut = new Customer(gateway);
//decimal actual = sut.CalculateWage(anyId);
decimal actual = sut.CalculateWage(Arg.Any<int>());
Assert.That(actual, Is.EqualTo(expectedWage).Within(0.1));
}
}
Arg.*
用于 arranging/stubbing 模拟行为。
它们并不意味着在进行测试时用作实际参数值
Argument matchers should only be used when specifying calls for the purposes of setting return values, checking received calls, or configuring callbacks (for example: with Returns
, Received
or When
). Using Arg.Is
or Arg.Any
in other situations can cause your tests to behave in unexpected ways.
引用How NOT to use argument matchers
[TestFixture]
public class CustomerTestsWithNSubstitute {
[Test]
public void CalculateWage_HourlyPayed_ReturnsCorrectWage() {
//Arrange
var gateway = Substitute.For<IDbGateway>();
var workingStatistics = new Business.Demo.WorkingStatistics()
{ PayHourly = true, HourSalary = 100, WorkingHours = 10 };
const int anyId = 1;
//Use Arg.* here
gateway.GetWorkingStatistics(Arg.Any<int>()).ReturnsForAnyArgs(workingStatistics);
const decimal expectedWage = 100 * 10;
var sut = new Customer(gateway);
//Act
decimal actual = sut.CalculateWage(anyId); //<-- Use actual value here
//Assert
Assert.That(actual, Is.EqualTo(expectedWage).Within(0.1));
}
}
我有一个客户 class,它接受 IDbGateway 接口作为构造函数参数。我需要使用 NUnit 和 NSubstitute 为 class 编写单元测试 CalculateWage_HourlyPayed_ReturnsCorrectWage。当我通过 anyId 时,我的单元测试工作正常。但我想传递 Arg.Any<int>()
而不是 anyId。目前我的测试失败了,因为 decimal actual = sut.CalculateWage(Arg.Any<int>());
给出了 NullReferenceException
。为什么我的代码适用于 anyId 值传递但不适用于 Arg.Any<int>()
?
目标成员如下
public class Customer
{
private readonly IDbGateway _gateway;
public Customer(IDbGateway gateway)
{
_gateway = gateway;
}
public decimal CalculateWage(int id)
{
WorkingStatistics ws = _gateway.GetWorkingStatistics(id);
decimal wage;
if (ws.PayHourly)
{
wage = ws.WorkingHours * ws.HourSalary;
}
else
{
wage = ws.MonthSalary;
}
return wage;
}
}
public interface IDbGateway
{
WorkingStatistics GetWorkingStatistics(int id);
}
public class DbGateway : IDbGateway
{
public WorkingStatistics GetWorkingStatistics(int id)
{
throw new NotImplementedException();
}
}
public class WorkingStatistics
{
public decimal HourSalary { get; set; }
public int WorkingHours { get; set; }
public decimal MonthSalary { get; set; }
public bool PayHourly { get; set; }
}
这是有问题的测试
[TestFixture]
public class CustomerTestsWithNSubstitute
{
[Test]
public void CalculateWage_HourlyPayed_ReturnsCorrectWage()
{
var gateway = Substitute.For<IDbGateway>();
var workingStatistics = new Business.Demo.WorkingStatistics()
{ PayHourly = true, HourSalary = 100, WorkingHours = 10 };
const int anyId = 1;
//gateway.GetWorkingStatistics(anyId).ReturnsForAnyArgs(workingStatistics);
gateway.GetWorkingStatistics(Arg.Any<int>()).ReturnsForAnyArgs(workingStatistics);
const decimal expectedWage = 100 * 10;
var sut = new Customer(gateway);
//decimal actual = sut.CalculateWage(anyId);
decimal actual = sut.CalculateWage(Arg.Any<int>());
Assert.That(actual, Is.EqualTo(expectedWage).Within(0.1));
}
}
Arg.*
用于 arranging/stubbing 模拟行为。
它们并不意味着在进行测试时用作实际参数值
Argument matchers should only be used when specifying calls for the purposes of setting return values, checking received calls, or configuring callbacks (for example: with
Returns
,Received
orWhen
). UsingArg.Is
orArg.Any
in other situations can cause your tests to behave in unexpected ways.
引用How NOT to use argument matchers
[TestFixture]
public class CustomerTestsWithNSubstitute {
[Test]
public void CalculateWage_HourlyPayed_ReturnsCorrectWage() {
//Arrange
var gateway = Substitute.For<IDbGateway>();
var workingStatistics = new Business.Demo.WorkingStatistics()
{ PayHourly = true, HourSalary = 100, WorkingHours = 10 };
const int anyId = 1;
//Use Arg.* here
gateway.GetWorkingStatistics(Arg.Any<int>()).ReturnsForAnyArgs(workingStatistics);
const decimal expectedWage = 100 * 10;
var sut = new Customer(gateway);
//Act
decimal actual = sut.CalculateWage(anyId); //<-- Use actual value here
//Assert
Assert.That(actual, Is.EqualTo(expectedWage).Within(0.1));
}
}