【发布时间】:2013-10-18 16:24:30
【问题描述】:
我正在尝试对这段代码进行单元测试,
public bool IsCityAvailable(Appointment appointment)
{
var city = _customerRepository.Find(appointment.CustomerId).City;
return _employeeRepository.Get.Count(x => x.City == city) > 0;
}
这是我的测试,
[SetUp]
public void Setup()
{
MockAppointmentRepository = new Mock<IRepository<Appointment>>();
MockCustomerRepository = new Mock<IRepository<Customer>>();
MockShiftRepository = new Mock<IRepository<Shift>>();
MockEmployeeRepository = new Mock<IRepository<Employee>>();
AppointmentService = new AppointmentService(MockCustomerRepository.Object, MockAppointmentRepository.Object, MockShiftRepository.Object, MockEmployeeRepository.Object);
Customer = new Customer()
{
Address = "88 Taraview Road NE",
City = "Calgary",
Email = "charles.norris@outlook.com",
FirstName = "Charles",
LastName = "Norris",
Id = 1,
Phone = "587-888-8882",
PostalCode = "X1X 1X1",
Province = "AB"
};
Employee1 = new Employee()
{
Address = "12 Saddletowne Road NW",
City = "Calgary",
Email = "johnny.bravo@outlook.com",
FirstName = "John",
LastName = "Bravo",
Id = 2,
Phone = "403-999-2222",
PostalCode = "X1X 1X1",
Province = "AB"
};
Employee2 = new Employee()
{
Address = "12 Saddletowne Road NW",
City = "Calgary",
Email = "johnny.bravo@outlook.com",
FirstName = "John",
LastName = "Bravo",
Id = 2,
Phone = "403-999-2222",
PostalCode = "X1X 1X1",
Province = "AB"
};
Appointment = new Appointment()
{
Id = 1,
Customer = Customer,
CustomerId = Customer.Id,
Employee = Employee1,
EmployeeId = Employee1.Id,
ScheduledTime = new DateTime(2013,10,15,18,30,00)
};
}
[Test]
public void IsCityAvailableShouldReturnAvailableWhenEmployeeInSameCityFound()
{
// ARRANGE
var employees = new List<Employee> { Employee1, Employee2 };
var result = new Mock<IQueryable<Employee>>();
result.Setup(r => r.GetEnumerator()).Returns(employees.GetEnumerator());
MockCustomerRepository.Setup(x => x.Find(It.IsAny<int>())).Returns(Customer);
MockEmployeeRepository.Setup(x => x.Get).Returns(result.Object);
// ACT
AppointmentService.IsCityAvailable(Appointment);
// ASSERT
MockCustomerRepository.Verify(x => x.Find(It.IsAny<int>()), Times.Once);
MockEmployeeRepository.Verify(x => x.Get, Times.Once);
}
我已经调试并单步执行找不到它所指的值 null,我的城市变量是正确的,约会参数已完全填充。有没有我没看到的东西?
这是单元测试的输出错误:
System.ArgumentNullException:值不能为空。参数名称: 论据
这里是堆栈跟踪:
System.ArgumentNullException : Value cannot be null.
Parameter name: arguments
at System.Linq.Expressions.Expression.RequiresCanRead(Expression expression, String paramName)
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection`1 arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at System.Linq.Queryable.Count(IQueryable`1 source, Expression`1 predicate)
at Zenwire.Services.AppointmentService.IsCityAvailable(Appointment appointment) in AppointmentService.cs: line 81
at Tests.Unit.Zenwire.Services.AppointmentServiceTests.IsCityAvailableShouldReturnAvailableWhenEmployeeInSameCityFound() in AppointmentServiceTests.cs: line 100
【问题讨论】:
-
_employeeRepository为空吗?有些东西会是空的。你只需要更加努力地寻找。实际上,我们都可以为您猜测,但无法调试代码,它可能是任何东西。 -
看起来像 // ACT AppointmentService.IsCityAvailable(Appointment); “约会”为空
-
当我单步执行时,会填充约会。我认为问题出在模拟设置上?
-
需要注意的一点是,虽然您的实际方法看起来很干净,但您违反了“最少知识原则”或“得墨忒耳定律”。有些人也将其称为点点滴滴,一般来说,您希望避免这样做。 “最少知识原则”说只与你的直接朋友交谈。在您的第一行应用程序代码中,您调用:
_customerRepository.Find(appointment.CustomerId).City可能没有更好的方法,但这意味着您必须连接一些东西才能使该行代码工作。随着时间的推移,这可能会使测试和维护变得困难。 -
您采用的方法在这种情况下可能最有意义。这里的替代方法是将客户传递给方法,您的调用代码可能永远不需要访问该方法。所以,它可能已经尽可能干净了,它更像是为未来做准备,因为这可能会导致非常困难的测试场景。
标签: c# unit-testing asp.net-mvc-4 moq