Testing Task-based WCF call - c#

I am converting the WCF calls I am making in an application to run asynchronously to ensure the GUI is responsive while it gets data. Mostly I am using these methods to populate the properties of a ViewModel.
For instance, here's my old and new code:
private async Task LoadDataItems()
{
//DataItems = Service.SelectDataItems();
DataItems = await Service.SelectDataItemsAsync();
}
Also, here's some test code using RhinoMocks:
//Doesn't set DataItems when LoadDataItems() is called
myWcfServiceClient.Stub(async client => await client.SelectDataItemsAsync()).Return(new Task<List<DataItemDto>>(() => new List<DataItemDto> { testDataItem }));
//NullReferenceException on SelectDataItemsAsync()
myWcfServiceClient.Stub(client => client.SelectDataItemsAsync().Result).Return(new List<DataItemDto> { testDataItem });
Basically, in my unit test, either DataItems isn't set or I get a NullReferenceException trying to fake out the result. This is probably as much a question on RhinoMocks than anything...

In RhinoMocks, you define the Result on the Task-based operation with Task.FromResult(...)
So, my test code would set up the result as follows:
myWcfServiceClient.Stub(client => client.SelectDataItemsAsync()).Return(Task.FromResult(new List<DataItemDto> { testDataItem }));
Simple and works great!

Related

Delay Returns with NSubstitute

I have an interface IDiscosClient, for testing/demo purposes while I'm developing the app, I want a mock to return a new model when the .GetSingle<T>() method is called with a random delay of between 1 and 5 seconds. This is mostly so I can see that all of my various loading spinner components and whatnot work.
So, I thought I'd be able to do something like this:
Fixture fixture = new();
fixture.Customize(new DiscosModelFixtureCustomizationNoLinks());
builder.Services.AddTransient(_ =>
{
IDiscosClient client = Substitute.For<IDiscosClient>();
DiscosObject obj = fixture.Create<DiscosObject>();
client.GetSingle<DiscosObject>(Arg.Any<string>()).Returns(Task.Delay(Random.Shared.Next(1000,5000)).ContinueWith(_ => obj));
return client;
});
However, while there seems to be a delay when I first call the method, once this has resolved, it just seems to return the completed task with the same model in it every time I call it for that IDiscosClient instance.
Is there a simple enough way to accomplish this?
So the issue is that the code above only creates a fresh Task the first time and then returns the same one (which has already completed) each subsequent time.
To fix this, we can either change the code above to:
client.GetSingle<DiscosObject>(Arg.Any<string>()).Returns(_ => Task.Delay(Random.Shared.Next(1000,5000)).ContinueWith(_ => obj));
Or, for legibilities sake, we can extract it into a method and make the whole code block:
builder.Services.AddTransient(_ =>
{
IDiscosClient client = Substitute.For<IDiscosClient>();
client.GetSingle<DiscosObject>(Arg.Any<string>()).Returns(GetDiscosObject);
return client;
});
async Task<DiscosObject> GetDiscosObject(CallInfo _)
{
await Task.Delay(Random.Shared.Next(1000, 5000));
return fixture.Create<DiscosObject>();
}

How to mock a method within a non-mocked class using Moq?

I want to test the Save() method which is residing inside the Contributor class. This method, in turn, opens a dialog which, when finished loading, actions an event that triggers the method that I want to mock - PushToPortal.
internal class Contributor
{
private readonly IEntryPointWrapper _entryPoint;
private readonly ISyncDialog _dialog;
public event Action OnPushToWeldCompleted;
internal void Save(Document document)
{
...
void Ptp() => PushToPortal(information);
_dialog.ShowDialog(Ptp);
}
}
When ShowDialog is called, OnLoadingCompleted += Ptp; is invoked.
The problem begins just here. PushToPortal looks like this:
internal virtual void PushToPortal(Information information)
{
var pushToPortal = Task.Run(() => {
var result = _entryPoint.ProcessElements(information);
});
pushToPortal.ContinueWith(task => OnPushToPortalCompleted?.Invoke(), TaskScheduler.FromCurrentSynchronizationContext());
}
Basically, when running the tests, they continue running while the async method is still processing and when asserting, the callback does not retrieve the needed information unless I use Thread.Sleep, which is not a solution that I'd like.
The working solution would be:
_entryPointMock.Setup(epm => epm.ProcessElements(It.IsAny<Information>()))
.Callback<WeldInformation>(information => actualWeldInformation = information)
.Returns(new InfoResult { Status = Status.Succeed, InfoCount = 1 });
Thread.Sleep(5000);
_contributor.Save(document);
I tried mocking the PushToPortal method and use a Callback to retrieve its arguments, without going into ProcessElements, but it does not seem to do anything at all.
_entryPointMock.Setup(epm => epm.ProcessElements(It.IsAny<Information>()))
.Returns(new InfoResult { Status = Status.Succeed, InfoCount = 1 });
var mock = new Mock<Contributor>();
mock.CallBase = true;
mock.Setup(x => x.PushToPortal(It.IsAny<Information>()))
.Callback<Information>(information => actualInformation = information);
_contributor.Save(document);
Therefore, how can I mock PushToPortal properly such that I retrieve the information, without actually entering the new thread which processes the elements? I am looking for a solution which does not imply changing the current code very much - an example which I thought of (and would not like to implement) would've been breaking down the functionality and returning a Task.

moq for mediator using generics in unit testing

I use cqrs and mediatr in .net core 3 webapi project. I want to unit test controller methods behavior, so when the method is called, mediator does it work as expected. I wrote testing code for one method and it works fine. Many code is omitted for brevity, I only used code which causes the error. So, working test:
var mockScrapedAd = ScrapedAd.CreateMockAd(DateTime.Now); //result of controller method
mediatrMock.Setup(m =>
m.Send(It.IsAny<QueryDetails>(),
It.IsAny<CancellationToken>())).
ReturnsAsync(() => mockScrapedAd); //mock for mediator,
// so when something with QueryDetails type is called, it should return result from above
var ret = await controller.Details(0); //should send QueryDetails via Mediatr
Assert.Equal(mockScrapedAd, ret.Value); //all good?
mediatrMock.Verify(x => x.Send(It.IsAny<QueryDetails>(), //was it called at all?
It.IsAny<CancellationToken>()));
This test works, but I will have to duplicate code for each controller method. The only thing that changes here is type of mediatr request (QueryDetails here) and mock for return.
So I tried to use generic method like here:
async Task TestBase<TK,K>(TK expectedResult,Func<Task<ActionResult<TK>>> callControllerMethod)
{
mediatrMock.Setup(m =>
m.Send(It.IsAny<K>(),
It.IsAny<CancellationToken>())).ReturnsAsync(() => expectedResult);
var ret = await callControllerMethod();
Assert.Equal(expectedResult, ret.Value);
mediatrMock.Verify(x => x.Send(It.IsAny<K>(),
It.IsAny<CancellationToken>()));
}
And the test suite will be easier:
var mockScrapedAd = ScrapedAd.CreateMockAd(DateTime.Now);
await TestBase<ScrapedAd,QueryDetails>(mockScrapedAd, async () => await controller.Details(0));
Basically all I changed is moved QueryDetails inside generic method. Mediator fails to recognize it and response is not called. What's wrong here?

Using Moq to mock an asynchronous method for a unit test

I am testing a method for a service that makes a Web API call. Using a normal HttpClient works fine for unit tests if I also run the web service (located in another project in the solution) locally.
However when I check in my changes the build server won't have access to the web service so the tests will fail.
I've devised a way around this for my unit tests by creating an IHttpClient interface and implementing a version that I use in my application. For unit tests, I make a mocked version complete with a mocked asynchronous post method. Here's where I have run into problems. I want to return an OK HttpStatusResult for this particular test. For another similar test I will be returning a bad result.
The test will run but will never complete. It hangs at the await. I am new to asynchronous programming, delegates, and Moq itself and I've been searching SO and google for a while learning new things but I still can't seem to get past this problem.
Here is the method I am trying to test:
public async Task<bool> QueueNotificationAsync(IHttpClient client, Email email)
{
// do stuff
try
{
// The test hangs here, never returning
HttpResponseMessage response = await client.PostAsync(uri, content);
// more logic here
}
// more stuff
}
Here's my unit test method:
[TestMethod]
public async Task QueueNotificationAsync_Completes_With_ValidEmail()
{
Email email = new Email()
{
FromAddress = "bob#example.com",
ToAddress = "bill#example.com",
CCAddress = "brian#example.com",
BCCAddress = "ben#example.com",
Subject = "Hello",
Body = "Hello World."
};
var mockClient = new Mock<IHttpClient>();
mockClient.Setup(c => c.PostAsync(
It.IsAny<Uri>(),
It.IsAny<HttpContent>()
)).Returns(() => new Task<HttpResponseMessage>(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
bool result = await _notificationRequestService.QueueNotificationAsync(mockClient.Object, email);
Assert.IsTrue(result, "Queue failed.");
}
What am I doing wrong?
Thank you for your help.
You're creating a task but never starting it, so it's never completing. However, don't just start the task - instead, change to using Task.FromResult<TResult> which will give you a task which has already completed:
...
.Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
Note that you won't be testing the actual asynchrony this way - if you want to do that, you need to do a bit more work to create a Task<T> that you can control in a more fine-grained manner... but that's something for another day.
You might also want to consider using a fake for IHttpClient rather than mocking everything - it really depends on how often you need it.
Recommend #Stuart Grassie's answer above.
var moqCredentialMananger = new Mock<ICredentialManager>();
moqCredentialMananger
.Setup(x => x.GetCredentialsAsync(It.IsAny<string>()))
.ReturnsAsync(new Credentials() { .. .. .. });
With Mock.Of<...>(...) for async method you can use Task.FromResult(...):
var client = Mock.Of<IHttpClient>(c =>
c.PostAsync(It.IsAny<Uri>(), It.IsAny<HttpContent>()) == Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK))
);
Try using ReturnsAsync.
In asynchronous methods it works, I believe the basis to solve your problem should be similar.
_mocker.GetMock<IMyRepository>()
.Setup(x => x.GetAll())
.ReturnsAsync(_myFakeListRepository.GetAll());

How can i call two methods asynchronously?

I have the following two methods:
private static void webservicecalls()
{
WebServiceOne();
WebServiceTwo();
}
So how i can call these two methods asynchronously instead of waiting for the first web service call to be complete before calling the second web service?
Update:
Now both WebSericeOne and WebServiceTwo have sub calls such as:
private static void WebServiceOne()
{
CallOne();
CallThree();
}
private static void WebServiceTwo()
{
CallTwo();
CallFour();
}
so i need the call to have the following sequence for the sub calls :-
CallOne();
CallTwo();
CallThree();
CallFour();
Depending on what are you using to implement webserviceone webservicetwo, it is quite likely that the web-service tooling itself will have full async support, so the first thing to do is: check that, and use the async API rather than the sync API.
If, for some reason, that does not exist - you could do something like:
var task = new Task(() => webservice1());
task.Start();
webservice2();
task.Wait();
(obviously you could run both fully async; I'm assuming in the above you just want to run them both in parallel, and "join" at the end)
Re your edit: if the order must be exactly "one","two","three","four", then you can't do them in parallel, so you would have to instead just run the entire thing in the background:
new Task(() => {
webservice1();
webservice2();
}).Start();
which will guarantee the execution order, sacrificing parallelism.
Action one = () => WebServiceOne();
Action two = () => WebServiceTwo();
one.BeginInvoke(null, null);
two.BeginInvoke(null, null);
I like using an Action.
private static void WebServiceCalls()
{
var someState = 3;
Action a1 = () => { WebserviceOne(); };
Action a2 = () => { WebserviceTwo(); };
a1.BeginInvoke(WebServiceCallBack, someState); //see code section below
a2.BeginInvoke(null, null); //fire and forget...
}
This also allows you to create a Callback for handling code:
void WebServiceCallBack(IAsyncResult result)
{
int state = (int)result.AsyncState;
//do more??
}
#Mark brings up a valid point: If you are working with a webservice within Visual studio, you can use the service reference configuration window to create the Channel Proxy class with async syntax. (I.e. with the BeginWebServiceOne and EndWebServiceOne which would preclude the need to create Async wrappers.)
Take a look at the task library here, and the navigation for the sub categories on the left
http://msdn.microsoft.com/en-us/library/dd537609.aspx

Categories