Moq callback with out parameter - c#

I'm trying to use Moq to mock a callback for the following method signature:
ResponseHeader AddIncentives(
Hs_transRow[] data,
out ResponseBody responseBody);
I want my callback to use the data which is passed in. However, I'm running into problems which I think are because the second parameter is an out parameter. I can setup and return data without problems, but the callback is an issue.
This is my current setup:
var addIncentiveResponseBody = new ResponseBody();
mockCoinsService
.Setup(service => service.AddIncentives(It.IsAny<Hs_transRow[]>(), out addIncentiveResponseBody))
.Callback((Hs_transRow[] data, ResponseBody body) =>
{
//I want to use the data variable here
})
.Returns(() => new ResponseHeader
{
action = ResponseHeaderAction.RESPONSE,
});
When I run this code as part of a unit test, I get the error:
Invalid callback. Setup on method with parameters (Hs_transRow[],ResponseBody&) cannot invoke callback with parameters (Hs_transRow[],ResponseBody).
I can see there is an ampersand difference, which I assume is because that parameter should be an out parameter. However, if I add the out keyword to the callback (and assign it a value within the callback), I get the build time error:
Delegate 'Action' does not take two arguments.
Is Moq unable to handle a callback for a method which has an out parameter, or am I doing something wrong?
[Edit] To clarify beyond any doubt, I am not asking how to set the value of the out parameter. This is already being done by the line:
var addIncentiveResponseBody = new ResponseBody();

This was pointed out in the comments by Jeroen Heier but adding it as an answer should make it more visible. Scott Wegner has written an OutCallback overload which can be used.
This is used as follows:
mockCoinsService
.Setup(service => service.AddIncentives(It.IsAny<Hs_transRow[]>(), out addIncentiveResponseBody))
.OutCallback((Hs_transRow[] data, ResponseBody body) =>
{
//I can now use the data variable here
})
.Returns(() => new ResponseHeader
{
action = ResponseHeaderAction.RESPONSE,
});

Related

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?

Mock HttpResponseMessage while unit testing API with Moq and AutoFixture

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);

Moq: Test parameters sent with sequence of method calls

I'm new to C# Moq (used Rhino Mochs in the past) and needing to test a sequence of calls to the same method. I found this cool solution that tests a sequence of return values:
http://haacked.com/archive/2009/09/29/moq-sequences.aspx/
public static class MoqExtensions
{
public static void ReturnsInOrder<T, TResult>(this ISetup<T, TResult> setup,
params TResult[] results) where T : class {
setup.Returns(new Queue<TResult>(results).Dequeue);
}
}
What I need to do is to test the values sent as a parameter to the method (rather than the values it returns) in a sequence of calls to the same method.
Rough outline ...
var expression = new MyExpressionThing();
processor.Setup(x => x.Execute(expected1)).Verifiable();
processor.Setup(x => x.Execute(expected2)).Verifiable();
processor.Setup(x => x.Execute(expected3)).Verifiable();
expression.ExecuteWith(processor.Object);
processor.Verify();
Here's what I've attempted but I'm getting the exception:
"System.ArgumentException : Invalid callback. Setup on method with parameters (String,Object[]) cannot invoke callback with parameters (String)."
// Arrange
var processor = new Mock<IMigrationProcessor>();
IList<string> calls = new List<string>();
processor.Setup(p => p.Execute(It.IsAny<string>()))
.Callback<string>(s => calls.Add(s));
// Act
var expr = new ExecuteScriptsInDirectoryExpression { SqlScriptDirectory = #"SQL2\1_Pre" };
expr.ExecuteWith(processor.Object);
// Assert
calls.ToArray().ShouldBe(new[]
{ "DELETE FROM PRE1A", "DELETE FROM PRE1B", "INSERT INTO PRE2\r\nLINE2" });
Looks like I'm using boilerplate code from the Moq "Getting Started" examples:
This link discusses this exception and links to the Moq code that fires it.
http://dailydevscoveries.blogspot.com.au/2011/04/invalid-callback-setup-on-method-with.html
I would use a callback to capture the parameter each time the mock is called, and then assert the result:
var parameters = new List<ParameterType>();
processor.Setup(x => x.Execute(It.IsAny<ParameterType>()))
.Callback<ParameterType>(param => parameters.Add(param));
CallCodeUnderTest(processor.Object);
Assert.That(parameters, Is.EqualTo(new[] { expected1, expected2, expected3 }));
Update: Based on the error message you quoted, it looks like the method you're mocking takes a second parameter that's a params object[]. You don't need to specify that parameter when you call the method (which is why you don't need it in the Setup lambda), but you do need to specify it in the generic type parameters to .Callback. Change your Callback line to:
.Callback<string, object[]>((s, o) => calls.Add(s));

Setting up moq and verifying that a method was called

Using Microsoft Test Framework and Moq I'm trying to verify if a log4net method was called.
[TestMethod()]
public void Log_Info_When_Stuff_Is_Done()
{
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
logMockObject.Verify(moqLog => moqLog.Info("do stuff got called"), Times.AtLeastOnce());
}
I get an exception on Verify call saying that
Expected invocation on the mock at least once, but was never
performed: moqLog => moqLog.Info("do stuff got called") No setups
configured. No invocations performed.
What am I doing wrong?
update the problem was with a getter for SampleClas.Log property. I was always returning LogManager.GetLogger(...); even when the property was already set to a ILogProxy. I was under impression that the property's get accessor won't be called because I've set up a proxy like so sampleObject.Log = logMockObject.Object;
Right now Moq is verifying that DoStuffAndLogInfo calls Info with the exact string "do stuff got called". If it's actually calling Info with a different argument, and you don't care what the actual argument is, use the following instead:
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());
The test is correctly set up.
Check your sut to see if Log.Info actually gets called inside the DoStuffAndLogInfo method.
This doesn't look to be the original poster's problem, but in my case I had a very similar error message. It was due to my .Verify() call before the actual execution. For example, this is wrong:
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
....but this is right:
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());

Register a default instance in StructureMap

I have a class (MyService) that has a static property (MyService.Context) which represents a current context (which is specific to currently logged in user, so it changes).
What i'm trying to achieve i
ObjectFactory.Initialize(x =>
{
x.For<IMyService>().Use<MyInstance>(c => c.Use(MyService.Context));
});
I.e. so that for every ObjectFactory.GetInstance<IMyService>() i get a reference to MyService.Context
Is that doable?
UPDATE
I can't use a singleton pattern since MyService.Context changes depending on the user making a request (via HttpContext).
In the pseudo-code above lambda parameter c represents a SM context, so that i can return a custom result for each request. I'm aware of SM's Intercept() but it's fired after the object is constructed - not instead.
If you can work with a property there is the possibility to add a OnCreation method. The Action provided is executed against the instance just after creation:
ObjectFactory.Initialize(x =>
{
x.For<IMyService>()
.Use<MyInstance>()
.OnCreation(x => x.Context = MyService.Context;
});
Or you can use lazy initialization and provide a Func to the Use method which is executed whenever a new instance is needed. This should execute in the right context:
ObjectFactory.Initialize(x =>
{
x.For<IMyService>()
.Use<MyInstance>(() => new MyInstance(MyService.Context);
});
I hope one of this methods works for you.
Provided that the MyService has a ctor argument for the IContext:
For<IContext>().Add(c => MyService.Context).Named("context");
For<IMyService>().Use<MyService>()
.Ctor<IContext>().Is(c => c.GetInstance<IContext>("context"));
or if you want to default the context for all dependees:
For<IContext>().Use(() => MyService.Context);
For<IMyService>().Use<MyService>();
The lambda expression will in both cases cause the context to be resolved upon requesting the MyService instance.

Categories