Reputation: 938
I have unit test with AutoFixture, NSubstitute and xUnit.
It pass on local dev machine in VS but fails on TeamCity.
Test:
[Theory, AutoNSubstituteData]
public async void GetList_StatusError_ShouldReturnBadRequest(
[Frozen] ICommentsService _commentsService,
[Frozen] IMerchantsService _merchantsService,
[Frozen] ICampaignsService _campaignsService)
{
// Arrange
var output = _fixture.Build<CommentsResult<CommentOutput>>()
.Without(w => w.Entity)
.With(x => x.Status, ServiceActionStatus.Error)
.Create();
_commentsService.List(Arg.Any<int>(), Arg.Any<string>()).Returns(output);
var controller = new CommentController(_commentsService, _merchantsService, _campaignsService);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
// Act
IHttpActionResult actionResult = await controller.GetList(null);
var contentResult = actionResult as BadRequestErrorMessageResult;
// Assert
contentResult.Should().NotBeNull();
contentResult.Message.Should().NotBeNullOrEmpty();
}
TeamCity error:
NSubstitute.Exceptions.AmbiguousArgumentsException:
Cannot determine argument specifications to use.
Please use specifications for all arguments of the same type. at NSubstitute.Core.Arguments.NonParamsArgumentSpecificationFactory.Create(Object argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications)
CommentsResult look like:
public class CommentsResult<T> : IServiceResult<T>
{
public T Entity { get; set; }
public string Message { get; set; }
public Exception Exception { get; set; }
public ServiceActionStatus Status { get; set; }
}
What is can be?
Upvotes: 4
Views: 2842
Reputation: 734
Usually this issue happens due to argument specifications which are not entirely consumed (e.g. you pass Arg.Any<T>()
to non-virtual method). There are a lot of potential scenarios how that could happen. The reason why you see that on particular environment might be a combination of the corrupted tests and the concurrency (trash from one test is consumed in other test that appeared to run on the same thread). The main problem here is that it might be really hard to troubleshoot the issue if you have a lot of tests, as each one could potentially leak an argument specification.
Recently I've created a diagnostics suite to help to troubleshoot this issue. It allows you to find the "leaked" argument specifications. Notice, it might significantly slow down the tests execution, so should be disabled afterwards.
Steps are following:
AmbiguousArgumentsException
exception is thrown, this trap should catch a culprit - the specification(s) which is a leftover from the previous test execution. The Spec
and CreationStack
field values should help you to find an exact place.Tune your code to trigger the static constructor of the DiagnosticsSubstitutionContext
class before tests execution. For instance, you might create a static constructor inside the AutoNSubstituteData
attribute class with the following content:
DiagnosticsSubstitutionContext.Init()
After the exception is thrown the next time, you should have information about broken specification, so you will find an exact place.
P.S. If you keep .pdb files during your tests execution, you should be able to see exact line of code where the broken specification was enqueued in addition to the method name.
Upvotes: 3