Mock HttpResponseMessage while unit testing API with Moq and AutoFixture - c#

I am writing unit tests for the existing Web API 2 project. For which i am using Ploeh Autofixture and Moq.
Test Method :
UPDATED
[Test]
public async Task Service1_TestMethod() {
//some code here
var fakeemail = FakeBuilder.Create<string>("test1234#test.com");
var fakeUserInvite =
FakeBuilder.Build<UserInvite>()
.With(i => i.EmailAddress, fakeemail)
.With(i => i.Username, fakeemail)
.Create();
var fakeUserToken = FakeBuilder.Create<string>();
var fakeHttpResponseMessage =
Fixture.Build<HttpResponseMessage>()
.With(h => h.StatusCode, HttpStatusCode.OK).Create();
//Here i am mocking another service method. Whose response is HttpResponseMessage.
Service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
var result = await Service1.AddUser( /* */);
}
Service1 Method :
public async Task<bool> AddUser(/* */)
{
var response = await Service2.AddUser(userInvite, userToken); // response is null even after mocking it.
// Add user code follows bassed on the above response.
}
If i comment the Service2.AddUser call then everything works. There is a lot of code in that method apart from this call. I am having problem with only this call. If this call returns the mocked HttpResponseMessage then everything works.
Service2 is an external API. I am just wondering how to mock HttpResponseMessage. Any help is appreciated.

The stub you create with:
service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
requires the actual call to be made with the exact same objects as the ones referenced by fakeUserInvite and fakeUserToken in order for Moq to return fakeHttpResponseMessage.
This is because Moq's argument matching verifies that the arguments specified in the stub are equal to the ones made in the actual call. If they are not, the stub won't match and Moq will return the default value for the method's return type – in this case null since HttpResponseMessage is a reference type.
To solve this problem, you can either make sure that the fakeUserInvite and fakeUserToken references are being passed to the actual service2.AddUser call or you can use somewhat less specific argument constraints.
Here's an example:
service2.Setup(i => i.AddUser(
It.Is<UserInvite>(u => u.EmailAddress == fakeEmail &&
u.Username == fakeEmail),
fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
Here we're stating that the AddUser method should be called with:
A UserInvite object whose EmailAddress and Username properties have the same value as fakeEmail as the first argument
The same value as fakeUserToken as the second argument
If the actual values of those arguments don't matter to your specific test scenario, you can tell Moq to always return fakeHttpResponseMessage regardless of what arguments AddUser is being called with by saying:
service2.Setup(i => i.AddUser(
It.IsAny<UserInvite>(),
It.IsAny<string>()))
.ReturnsAsync(fakeHttpResponseMessage);

Related

How can I setup a multi-item list with moq

I'm trying to write a unit test for my method but failed. I want to return the list with the 2 item response of GetMyRequest with Mock(package Moq), then I run Task.WhenAll with the response returned with my method. So I used the SetupSequence method but it returned a single-item list. How can I return a multi-item list in my test.
public void MyMethod()
{
ProductService = new Mock<IProductService>();
var myResponse = myStringList.Select(async x => await _myService.GetMyRequest(x, null, null)).ToList();
//my response type -> List<Task<ResponseModel>>
var myResponses = await Task.WhenAll(myResponse);
}
I want myResponses multi-item list with mocking but it single-item.
Unit tests
public async Task InitializeAsync(){
ServiceResponse = Fixture.Build<MyModel>().CreateMany(2).ToList();
MyService = new Mock<IProductService>();
MyService.SetupSequence(service => service.GetMyRequest(It.IsAny<string>(), null, null))
.ReturnsAsync(ServiceResponse[0])
.ReturnsAsync(ServiceResponse[1]);
}
TL; DR: You can't return multiple items for your GetMyRequest
SetupSequence means that you want to setup your GetMyRequest in a way that multiple calls against it will result with different responses.
For the first call you will receive the value of ServiceResponse[0]
For the second call you will receive the value of ServiceResponse[1]
According to my understanding the return type of GetMyRequest is Task<ServiceResponse> , that's why you can't define a mock to return Task<IEnumerable<ServiceResponse>> or something similar.

How to mock ElasticSearch NEST's GetAsync

I'm trying to get one document from my ElasticSearch instance using GetAsync. I do it something like this
var document= await client.GetAsync<MyDocument>("documentId");
return document.Source;
I'd like to mock out this call in a unit test. I tried doing something like this
[Fact]
public async Task TestGetDocument_ExpectSuccess()
{
var mockDocument = new Mock<IGetResponse<MyDocument>>(MockBehavior.Strict);
mockDocument
.Setup(r => r.Source)
.Returns(_myDocument);
var mockClient = new Mock<IElasticClient>(MockBehavior.Strict);
mockClient
.Setup(client => client.GetAsync(
_documentId,
It.IsAny<Func<GetDescriptor<MyDocument>, IGetRequest>>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(mockDocument.Object);
// ...
}
But when I do that, the instantiation of mockClient gives this error
'ISetup<IElasticClient, Task<GetResponse<MyDocument>>>' does not contain a definition for 'ReturnsAsync' and the best extension method overload 'SequenceExtensions.ReturnsAsync<IGetResponse<MyDocument>>(ISetupSequentialResult<Task<IGetResponse<MyDocument>>>, IGetResponse<MyDocument>)' requires a receiver of type 'ISetupSequentialResult<Task<IGetResponse<MyDocument>>>' [Foo.Bar.ElasticSearch.UnitTests]csharp(CS1929)
I'm confused by the SequenceExtensions bit in the error since I'm not using SetupSequence (if that's what it is referring to). I tried changing the responseMock type to GetResponse<ElasticHitContainer>, and it gets rid of the compile error, but now I cannot properly mock out the return value of Source since I'm not using an interface.
Anyone know how I can get around this?

How to mock a method inside the same class being tested?

I am creating some unit tests for a method ValidateObject in a service ObjectService. The ValidateObject method calls another method ValidateObjectPropertyB. I want to mock the calls to the last method.
The ObjectService and relevant method look like this:
public class ObjectService : IObjectService
{
public bool ValidateObject(object objectToValidate)
{
return
!String.IsNullOrEmpty(objectToValidate.PropertyA) &&
ValidateObjectPropertyB(objectToValidate.PropertyB, currentUserId);
}
public bool ValidateObjectPropertyB(long propertyB, long userId)
{
return validationResult;
}
}
Right now my Test class ObjectServiceTest contains the following code:
public class ObjectServiceTest
{
var objectToValidate = new Object(validPropertyA, validPropertyB);
using(var mock = new AutoMock.GetStrict())
{
var mockObjectService = new Mock<IObjectService>();
mockObjectService.callBase = true;
mockObjectService.Setup(s => s.ValidateObjectPropertyB(objectToValidate.PropertyB, _user.Id)).Returns(true);
var service = mock.Create<ObjectService>();
var result = service.ValidateObject(objectTovalidate);
Assert.IsTrue(result);
}
}
The above test fails because result is false, the for PropertyA succeeds
What am I doing wrong?
ValidateObject works in part by calling ValidateObjectPropertyB. I am presuming you are wanting to mock this second method so that you can demonstrate that ValidateObject does indeed call ValidateObjectPropertyB (provided !String.IsNullOrEmpty(objectToValidate.PropertyA) evaluates to true)
If this is the case then you are testing implementation detail, which generally you shouldn't do. Consider a function that took two integer values and returned their sum, you would want to verify that when this function was passed 3 and 5 it returned 8, you should not test that it arrived at this answer by using a particular method/class under the hood because this is not relevant to the desired outcome and should in future you decide you wished to refactor your code the test would likely start failing even if the code still returned the desired result.
Looking at your code, it seems that return value of ValidateObject is not directly dependent on the method call to ValidateObjectPropertyB but rather the value of validationResult. It is this value that you must set to properly test ValidateObject.
One way to achieve what you are asking would be to make ValidateObjectPropertyB virtual, then create a derived class that overrides this method to return what ever you want. However I do not recommend doing this purely for the sake of unit testing.

C# FakeItEasy and Method Chaining: Only First Call Is Recognized

I have a call to a factory interface that creates an IMachine in a command handler. This returned IMachine from the factory has methods that can be chained together to create itself inside of a builder class. The problem I am running into with FakeItEasy right now is that it only recognized the first call (which is WithSpeeds) unless I configure every method call to return a fake IMachine. Is there a way not to configure every single call or have FakeItEasy recognize every method call on the chain? I know I must be doing something incorrect because if i use OrderAssertions, and fail the order on purpose without setting up my fake machine, it shows calls were made to all the methods. Thanks for the help.
Part of the Command Handler's Method
public void Handle(FooCommand commandParm)
{
var entity = new Entity.Builder
{
Machine = _factory.CreateMachine(commandParm.MachineName)
.WithSpeeds(commandParm.ProcessingSpeed, commandParm.StartupSpeed, commandParm.ShutDownSpeed)
.WithOils(commandParm.Lubrication, commandParm.FinishingOil)
};
}
Test
[TestMethod]
public void HandleSetMachineSettings_should_build_machine()
{
// Arrange
var settings = CommandUtilities.ReturnFooCommand();
var _factory = A.Fake<IMachineFactory>();
var machine = A.Fake<IMachine>();
A.CallTo(() => _factory.CreateMachine(settings.MachineName)).Returns(machine);
// Act
_handler.Handle(settings);
// Assert
machine.Should().NotBeNull();
A.CallTo(machine).Where(x => x.Method.Name.Equals("set_MachineNumber")).WhenArgumentsMatch(arg => arg.Get<int>(0) == settings.MachineNumber).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => machine.WithSpeeds(commandParm.ProcessingSpeed, commandParm.StartupSpeed, commandParm.ShutDownSpeed)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => machine.WithOils(commandParm.Lubrication, commandParm.FinishingOil)).MustHaveHappened(Repeated.Exactly.Once);
}
I take it that WithSpeeds and WithOils both return an IMachine, yes?
The problem is:
_factory.CreateMachine returns one IMachine, machine from your setup
machine.WithSpeeds returns a fake IMachine that FakeItEasy makes up. This is not machine, but is a different fake, call it "machine2"
machine2.WithOils returns yet another fake machine
Your Assert block suggests that you expected the same machine to be returned at each step of the builder chain. Try inserting
A.CallTo(machine)
.WithReturnType<IMachine>()
.Returns(machine);
after A.CallTo(() => _factory.CreateMachine()).Returns(machine);
That way machine will keep returning itself, and the appropriate properties will be set on it and whatnot.

Rhino Mocks, how can I perform an action after setting a Stub property

I have a simple requirement, but I seem to be struggling.
I have created a stub that mocks an interface that includes a Property :
public interface IMockIRuleRuningViewModel : IRuleRunningViewModel
{
int Id { get; set; }
}
And the mock is :
var mock = MockRepository.GenerateStub<IMockIRuleRuningViewModel>();
Now I want to mock an action that I would have put in a setter for this Property, and here is my attempt :
mock.Stub(x => x.Id).WhenCalled(
o =>
{
var engine = new RulesEngine(mock);
mock.ProcessRuleEngineResults(engine.RunRule("Id"));
});
But I keep getting this Exception :
You are trying to set an expectation on a property that was defined to use PropertyBehavior.
Instead of writing code such as this: mockObject.Stub(x => x.SomeProperty).Return(42);
You can use the property directly to achieve the same result: mockObject.SomeProperty = 42;
The following works for me:
HttpResponseBase response = MockRepository.GenerateMock<HttpResponseBase>();
// stub the getter
response.Stub(r => r.StatusCode).Return((int)HttpStatusCode.OK);
// Stub the setter
response.Stub(r => r.StatusCode = Arg<int>.Is.Anything).WhenCalled( o =>
{
Console.WriteLine("called");
});
Since what I'm actually trying to do is model the case where you can get but not set the status code (because headers have already been sent), I don't do WhenCalled(), I do this:
response.Stub(r => r.StatusCode = Arg<int>.Is.Anything)
.Throw(new HttpException("Server cannot set status after HTTP headers have been sent"));
You have to use MockRepository.GenerateMock not MockRepository.GenerateStub. I don't know why.
If you want to verify the behavior of the SUT (system under test), you should use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub (stub will not cause a test to fail).
I assume that you are testing RulesEngine in this test (because it is only real object I see). Here is a sample test, which verifies behavior of engine, when "Id" rule was executed:
// Arrange
var model = MockRepository.GenerateMock<IMockIRuleRuningViewModel>();
model.Expect(m => m.ProcessEngineResults(42));
RulesEngine engine = new RulesEngine(model);
// Act
engine.RunRule("Id");
// Assert
model.VerifyAllExpectations();

Categories