测试异步方法产生奇怪的结果
Testing async method produces weird result
当我运行我的测试代码正常时,NUnit 通知我测试失败。 result.Contacts
的值为 3 而不是预期的 1。当测试代码为 运行 并且在测试代码中的 assert 语句上设置断点时,测试不会失败。我怀疑这是与多线程相关的问题。
这是我的测试代码
[Test]
public async Task Method_Scenario_IncreasesCount()
{
// Arrange
const int employeeId = 1;
const string managerId = "asdf";
// Act
var result = await _uut.Contact(managerId , employeeId);
// Assert
Assert.That(result.Contacts, Is.EqualTo(1));
}
这是被测代码
public async Task<MyObject> Contact(string managerId, int employeeId)
{
var today = DateTime.UtcNow.Date;
var myStoredObject = _myObjectRepository.GetAll().Include(p => p.Employee).First(x => x.Employee.Id == employeeId);
myStoredObject.Contacts += 1;
myStoredObject.LastContact = today;
var dates = new List<DateTime>
{
myStoredObject.FirstDate,
myStoredObject.SecondDate,
myStoredObject.ThirdDate
};
if (!dates.Contains(today))
{
await _logging.Log(myStoredObject, Log.Extra);
await _myObjectRepository.UpdateAsync(myStoredObject);
}
return myStoredObject;
}
_myObjectRepository
和 _logging
对象使用 Moq
模拟; myStoredObject
是我预定义的,所以我知道 Contacts 的值是 0。
为什么只有在assert 语句上使用断点时测试才能通过?我该如何解决这个问题?
编辑
我也试过使用 Moq
来做到这一点:
_mock.Verify(r => r.UpdateAsync(It.Is<MyObject>(m => m.Contacts == 1)));
但这也失败了,MockException 说:
Expected invocation on the mock at least once, but was never performed.
但是,如果我单步执行程序,我可以看到调用此方法的 MyObject
具有 Contacts = 1
.
如果没有看到您的 [SetUp]
代码,很难说出是什么导致了您的问题。我注意到你的模拟和被测单元是成员变量——也许与另一个测试共享状态有问题。我能够编写相同的测试,并且始终如一地通过
[Test]
public async Task Method_Scenario_IncreasesCount()
{
// Arrange
const int employeeId = 55378008;
var existingEntity = new MyObject {Employee = new Employee {Id = employeeId}};
var repo = Mock.Of<IMyObjectRepo>(r => r.GetAll() == new[] {existingEntity}.AsQueryable());
var uut = new MyUut(repo, Mock.Of<ILog>());
// Act
var entity = await uut.Contact(string.Empty, employeeId);
// Assert
Assert.That(entity.Contacts, Is.EqualTo(1));
Mock.Get(repo).Verify(r => r.UpdateAsync(entity));
}
当我运行我的测试代码正常时,NUnit 通知我测试失败。 result.Contacts
的值为 3 而不是预期的 1。当测试代码为 运行 并且在测试代码中的 assert 语句上设置断点时,测试不会失败。我怀疑这是与多线程相关的问题。
这是我的测试代码
[Test]
public async Task Method_Scenario_IncreasesCount()
{
// Arrange
const int employeeId = 1;
const string managerId = "asdf";
// Act
var result = await _uut.Contact(managerId , employeeId);
// Assert
Assert.That(result.Contacts, Is.EqualTo(1));
}
这是被测代码
public async Task<MyObject> Contact(string managerId, int employeeId)
{
var today = DateTime.UtcNow.Date;
var myStoredObject = _myObjectRepository.GetAll().Include(p => p.Employee).First(x => x.Employee.Id == employeeId);
myStoredObject.Contacts += 1;
myStoredObject.LastContact = today;
var dates = new List<DateTime>
{
myStoredObject.FirstDate,
myStoredObject.SecondDate,
myStoredObject.ThirdDate
};
if (!dates.Contains(today))
{
await _logging.Log(myStoredObject, Log.Extra);
await _myObjectRepository.UpdateAsync(myStoredObject);
}
return myStoredObject;
}
_myObjectRepository
和 _logging
对象使用 Moq
模拟; myStoredObject
是我预定义的,所以我知道 Contacts 的值是 0。
为什么只有在assert 语句上使用断点时测试才能通过?我该如何解决这个问题?
编辑
我也试过使用 Moq
来做到这一点:
_mock.Verify(r => r.UpdateAsync(It.Is<MyObject>(m => m.Contacts == 1)));
但这也失败了,MockException 说:
Expected invocation on the mock at least once, but was never performed.
但是,如果我单步执行程序,我可以看到调用此方法的 MyObject
具有 Contacts = 1
.
如果没有看到您的 [SetUp]
代码,很难说出是什么导致了您的问题。我注意到你的模拟和被测单元是成员变量——也许与另一个测试共享状态有问题。我能够编写相同的测试,并且始终如一地通过
[Test]
public async Task Method_Scenario_IncreasesCount()
{
// Arrange
const int employeeId = 55378008;
var existingEntity = new MyObject {Employee = new Employee {Id = employeeId}};
var repo = Mock.Of<IMyObjectRepo>(r => r.GetAll() == new[] {existingEntity}.AsQueryable());
var uut = new MyUut(repo, Mock.Of<ILog>());
// Act
var entity = await uut.Contact(string.Empty, employeeId);
// Assert
Assert.That(entity.Contacts, Is.EqualTo(1));
Mock.Get(repo).Verify(r => r.UpdateAsync(entity));
}