Closed reddy6ue closed 5 years ago
Hello @reddy6ue,
All you need to do is provide the default values for this call when you set it up. It's how Moq always worked and I have to do the same for my own tests as well.
Simply do:
activityRepo.Setup(p => p.AddAsync(It.IsAny<FakeData>(), null, default(CancellationToken)))
.Returns<FakeData>(a =>
Task.FromResult(
new CosmosResponse<FakeData>(fakeData, null)));
When I do this, I get a System.ArgumentException with the error Invalid callback. Setup on method with 3 parameter(s) cannot invoke callback with different number of parameters (1)
error.
That's weird. Can you change them with It.IsAny
?
activityRepo.Setup(p => p.AddAsync(It.IsAny<FakeData>(), It.IsAny<RequestOptions>(), It.IsAny<CancellationToken>))
.Returns<FakeData>(a =>
Task.FromResult(
new CosmosResponse<FakeData>(fakeData, null)));
Tried that too. Didn't work. I think it has a problem with the fact that my method call sends only one parameter.
That doesn't really make sense because calling a method with optional parameters means that the optional parameters are defaulted. They are still invoked though. Are you sure you are setting it up correctly? Did you try checking how i did it on my tests? I think it's the way you do Returns
.
I know it doesn't make sense. That's why I'm struggling with it. I changed my AddAsync
methods to send the two additional parameters as null
, and default(CancellationToken)
and the error is still occurring. Baffling.
Can you please paste the full test code so I can debug it locally?
Btw, looking at the code you submitted initially, you are creating a fakeDataRepo but you are setting up an activityRepo. Is that intended?
Meant to type in fakeDataRepo.
Yeah, paste the test including any setup if possible please. I can’t reproduce it.
Here's the only thing I've done differently. I created a root entity class called SharedCosmosEntity
which looks like this.
public interface ISharedCosmosEntity
{
string CosmosEntityName { get; set; }
}
All these contortions in the code are to make sure that my collection name is the class name.
public class SharedCosmosEntity : ISharedCosmosEntity
{
[JsonProperty("id")]
public string Id { get; set; }
// todo: This is not working. Need to figure out why
[JsonProperty("CosmosEntityName")]
public string CosmosEntityName
{
get => this.GetType().Name;
set => value = this.GetType().Name;
}
}
And each entity looks like this.
public class Activity: SharedCosmosEntity
{
public string SomeProp {get; set;}
}
Here's my test.
public class ActivityManagementServiceTest
{
private ActivityManagementService activityManagementService = null;
public ActivityManagementServiceTest()
{
var activityRepo = new Mock<ICosmosStore<Activity>>();
var fakeActivity = ActivityManagementServiceData.CreateActivityOne();
var document = fakeActivity.ConvertObjectToDocument();
var resourceResponse = document.ToResourceResponse(HttpStatusCode.OK);
activityRepo.Setup(p =>
p.AddAsync(It.IsAny<Activity>(),
null, default(CancellationToken)))
.Returns<Activity>(a =>
Task.FromResult(
new CosmosResponse<Activity>(fakeActivity, resourceResponse)));
activityManagementService = new ActivityManagementService(activityRepo.Object);
}
[Fact]
public void StoreUniqueActivity_ValidInput_ReturnActivityObject()
{
var fakeActivity = ActivityManagementServiceData.CreateActivityOne();
var storeActivity = pActivityManagementService.StoreUniqueActivityAsync(fakeActivity);
Assert.True(true);
}
}
The failure occurs in the Test Constructor before it ever hits the test.
You don not need to deal with the CosmosEntityName
property. Cosmonaut will do that for you.
Can you change this:
.Returns<Activity>(a => Task.FromResult(new CosmosResponse<Activity>(fakeActivity, resourceResponse)));
to this:
.ReturnsAsync(new CosmosResponse<Activity>(fakeActivity, resourceResponse))
That did the trick! Thanks for helping me out.
I am facing the following problems with Moq. I am mocking an
ICosmosStore
repository to write unit tests in the service layer.I get the error
Error CS0854 An expression tree may not contain a call or invocation that uses optional arguments
The root cause is that
AddAsync
has two other optional parametersRequestOptions
andCancellationToken
which trips up Moq. When I add the other two parameters, it obviously fails because I didn't setup the method that takes a single parameter. The problem is not with Cosmonaut per se, but it'll really help with a very popular mocking framework to also provide a version ofAddAsync
in the interface without the two optional parameter that just delegates to the method with the two optional parameter not being used.