【发布时间】:2017-07-07 19:04:52
【问题描述】:
我正在使用 NUnit、Shouldly 和 Entity Framework 内存中 SQLite 数据库进行集成测试,但遇到了两个不执行任何数据库调用的测试用例(未执行 await)。
控制器:
[HttpPost("DeleteOrganisations")]
public async Task<IActionResult> DeleteOrganisations([FromBody] DeleteOrganisationsModel model)
{
//Test case 2 fails here
if (model == null || !ModelState.IsValid)
{
return Ok(new GenericResultModel(_localizer["An_unexpected_error_has_occurred_Please_try_again"]));
}
List<OrganisationModel> organisations = (await _organisationService.GetOrganisations(model.OrganisationIds)).ToList();
//Test case 3 fails here
if (organisations == null || organisations.Count == 0)
{
return Ok(new GenericResultModel(_localizer["Could_not_find_organisations"]));
}
StatusModel status = await _statusService.GetStatus(StatusTypeEnum.StatusType.Organisation, StatusEnum.Status.Removed);
if (status == null)
{
return Ok(new GenericResultModel(_localizer["Could_not_find_status"]));
}
foreach (OrganisationModel organisation in organisations)
{
organisation.StatusId = status.Id;
}
List<OrganisationModel> updatedOrganisations = (await _organisationService.UpdateOrganisations(organisations)).ToList();
if (updatedOrganisations == null || updatedOrganisations.Count == 0)
{
return Ok(new GenericResultModel(_localizer["Could_not_remove_organisations"]));
}
if (updatedOrganisations.Count == 1)
{
return Ok(new GenericResultModel { Id = updatedOrganisations[0].Id });
}
return Ok(new GenericResultModel { Count = updatedOrganisations.Count });
}
测试:
[TestFixture]
public class DeleteOrganisations : TestBase
{
private OrganisationController _organisationController;
[OneTimeSetUp]
public void OneTimeSetUp()
{
//Controller
_organisationController = new OrganisationController(null, Mapper, OrganisationService, StatusService, AuthenticationService);
//Object Mother
ObjectMother.InsertTestData();
}
public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = new List<int>() { 1 } }, 0, 1).SetName("DeleteOrganisations_Should_Delete_Data_When_OrganisationId_Exist");
yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = null }, 0, 0).SetName("DeleteOrganisations_Should_Not_Delete_Data_When_Null");
yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = new List<int>() { 2 } }, 0, 0).SetName("DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist");
}
}
[Test, TestCaseSource(nameof(TestCases))]
public async Task Test(DeleteOrganisationsModel model, int removedOrganisationCountBefore, int removedOrganisationCountAfter)
{
//Before
int resultBefore = Database.Organisation.Include(o => o.Status).Count(o => o.Status.Name == StatusEnum.Status.Removed.ToString());
resultBefore.ShouldBe(removedOrganisationCountBefore);
//Delete
await _organisationController.DeleteOrganisations(model);
//After
int resultAfter = Database.Organisation.Include(o => o.Status).Count(o => o.Status.Name == StatusEnum.Status.Removed.ToString());
resultAfter.ShouldBe(removedOrganisationCountAfter);
}
}
测试用例 1 通过,因为
StatusModel status = await _statusService.GetStatus(StatusTypeEnum.StatusType.Organisation, StatusEnum.Status.Removed);
被调用并等待结果。
测试用例 2 和 3 失败,因为函数中从来没有 await,(if 语句)。
消息:System.NullReferenceException:对象引用未设置为 一个对象的实例。
我可能可以为不执行任何等待语句的结果创建另一个测试并跳过新测试函数的异步任务,但随后我会收到以下消息:
因为没有等待这个调用,所以执行当前方法 在呼叫完成之前继续。考虑应用“等待” 调用结果的运算符。
测试可能会通过,但我不喜欢两个测试加上语法错误的想法。
你会怎么做?
编辑
例外:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
堆栈跟踪:
Test Name: DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist
Test FullName: MyProject.Test.Api.Administration.Organisation.DeleteOrganisations.DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist
Test Source: C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProject.Test\Api\Administration\Organisation\DeleteOrganisations.cs : line 42
Test Outcome: Failed
Test Duration: 0:00:02.48
Result StackTrace: at MyProject.Api.Controllers.Administration.OrganisationController.<DeleteOrganisations>d__8.MoveNext() in C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProject.Api\Controllers\Administration\OrganisationController.cs:line 114
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MyProject.Test.Api.Administration.Organisation.DeleteOrganisations.<Test>d__4.MoveNext() in C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProjectTest\Api\Administration\Organisation\DeleteOrganisations.cs:line 49
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)
at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context)
Result Message: System.NullReferenceException : Object reference not set to an instance of an object.
【问题讨论】:
-
@Will 我没有包含任何异常详细信息,因为我认为它没有任何有用的信息,但我已经用异常和堆栈跟踪编辑了我的问题
-
没有有用的信息?哈哈哈。您的问题就在这里:
Organisation.DeleteOrganisations。你waiting 在那个方法中的某个东西上,不管它是什么都在抛出异常。 这与你的测试方法完全无关。去DeleteOrganizations下断点,调试测试看看什么是空的。 -
让我们假装我没这么说:)
-
哦,不。截图,所以不要打扰删除您的评论。这将在你的职业生涯中一直困扰着你。需要注意的是,您永远不会不检查调用堆栈以找出问题所在。是的,出于羞耻和自我厌恶,是的,但是您将能够更快地修复错误。 :)
-
Lmao,感谢您为我指明了正确的方向,请注意安全先生
标签: c# testing asynchronous nunit integration-testing