I'm using Microsoft Fakes to Shim an async method that invokes another method to get an implemented DbContext. Because database connection string is not supplied in the Unit Test while the method being invoked inside the async method needs it. Shim will not only skip the method that uses the connection string, but returns a customizable DbContext.
Here is the aysnc method implementation:
public async Task<AccountDataDataContext> GetAccountDataInstance(int accountId)
{
var account = await this.Accounts.FindAsync(accountId);
return AccountDataDataContext.GetInstance(account.AccountDataConnectionString);
}
However, I'm not familiar with Shim async method. What I did look like this:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 = (x, y, z) => new Task<AccountDataEntities.AccountDataDataContext>(() =>
{
return new SampleContext();// This is the fake context I created for replacing the AccountDataDataContext.
});
And SampleContext is implementing AccountDataDataContext as follows:
public class SampleContext: AccountDataDataContext
{
public SampleContext()
{
this.Samples = new TestDbSet<Sample>();
var data = new AccountDataRepository();
foreach (var item in data.GetFakeSamples())
{
this.Samples.Add(item);
}
}
}
Below is the code snippet for the test case:
[TestMethod]
public async Task SampleTest()
{
using (ShimsContext.Create())
{
//Arrange
SamplesController controller = ArrangeHelper(1);// This invokes the Shim code pasted in the second block and returns SamplesController object in this test class
var accountId = 1;
var serviceId = 2;
//Act
var response = await controller.GetSamples(accountId, serviceId);// The async method is invoked in the GetSamples(int32, int32) method.
var result = response.ToList();
//Assert
Assert.AreEqual(1, result.Count);
Assert.AreEqual("body 2", result[0].Body);
}
}
As the result, my test case is running forever. I think I might write the Shim lamdas expression completely wrong.
Any suggestion? Thank you.
You don't want to return a new Task. In fact, you should never, ever use the Task constructor. As I describe on my blog, it has no valid use cases at all.
Instead, use Task.FromResult:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 =
(x, y, z) => Task.FromResult(new SampleContext());
Task also has several other From* methods that are useful for unit testing (e.g., Task.FromException).
Related
I have created an abstract class that implements Polly that I want to write unit tests for.
In one of my tests I want to test how my method handles certain values of PolicyResult.FinalException.
Because the returned PolicyResult is null I get a NullReferenceException when evaluating result.FinalException
How do I mock the returned result?
What I have so far:
public class AbstractRestClientTest
{
private AbstractRestClient _sut;
private Mock<IRestRequestFactory> _requestFactoryMock;
private Mock<IRestClientFactory> _restClientfactoryMock;
private Mock<IPollyPolicyFactory> _policyFactoryMock;
private Mock<IAsyncPolicy> _policyMock;
private const string DUMMY_URL = "http://dosomething.com/getmesomething";
[SetUp]
public void SetUp()
{
_requestFactoryMock = new Mock<IRestRequestFactory>();
_restClientfactoryMock = new Mock<IRestClientFactory>();
_policyFactoryMock = new Mock<IPollyPolicyFactory>();
var settings = new MockSettings();
_policyMock = new Mock<IAsyncPolicy>();
_policyFactoryMock.Setup(mock =>
mock.CreateAsyncResiliencePolicy(settings))
.Returns(_policyMock.Object);
_sut = new MockRestClient(settings, _restClientfactoryMock.Object,
_policyFactoryMock.Object,
_requestFactoryMock.Object);
}
}
public class MockRestClient : AbstractRestClient
{
public MockRestClient(RestSettings settings, IRestClientFactory restClientFactory, IPollyPolicyFactory pollyPolicyFactory,
IRestRequestFactory requestFactory) : base(settings, restClientFactory, pollyPolicyFactory, requestFactory) {
}
}
public class MockSettings : RestSettings
{
public override string Naam => "TestSettings";
}
------------------ EDIT 1 --------------------------------
With Nkosi's comment I got a little bit further but still PolicyResult returned by _policy.ExecuteAndCaptureAsync is null. This leads me to believe that there is something wrong in the way that I mock that method.
I changed my test to the following but still it returns `null``:
[Test]
public async Task HandleRequest_IfFinalExceptionNotNull_ThenThrowsException()
{
var mockResult = new Mock<IRestResponse<int>>();
PolicyResult<IRestResponse<int>> result = PolicyResult<IRestResponse<int>>.Failure(mockResult.Object, new Context());
//Is the following mock correctly setup?
_policyMock.Setup(mock => mock.ExecuteAndCaptureAsync(It.IsAny<Func<Task<IRestResponse<int>>>>()))
.ReturnsAsync(result);
var url = new Url(DUMMY_URL);
Assert.ThrowsAsync<Exception>(() => _sut.GetResult<int>(url));
}
I evaluated the parameters needed for ExecuteAndCapture and changed my setup for this method accordingly, what am I doing wrong?
Based on the publicly available source code on GitHub, there really is no need to mock that class. While it does have an internal constructor, static factory methods exist that should allow for the creation of your desired instance
For example
Context context = //...created as needed
PolicyResult<TestResponse> result = PolicyResult<TestResponse>.Failure(..., context);
Choose the right combination to satisfy the expected result in your test.
The issue was I was mocking the wrong version of ExecuteAndCaptureAsync, I needed to mock the method with the following signature:
`Task<PolicyResult> ExecuteAndCaptureAsync(Func<CancellationToken, Task> action, CancellationToken cancellationToken);`
So after I changes my SetUp accordingly the test succeeded:
[Test]
public async Task HandleRequest_IfFinalExceptionNotNull_ThenThrowsException()
{
var mockResult = new Mock<IRestResponse<int>>();
PolicyResult<IRestResponse<int>> result = PolicyResult<IRestResponse<int>>.Failure(mockResult.Object, new Context());
_policyMock.Setup(mock => mock.ExecuteAndCaptureAsync(
It.IsAny<Func<CancellationToken, Task<IRestResponse<int>>>>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(result);
var url = new Url(DUMMY_URL);
Assert.ThrowsAsync<Exception>(() => _sut.GetResultaat(url, new CancellationToken()));
}
I have a this code
public class ClassToTest
{
private readonly IRepository repository;
public ClassToTest(DI GOES HERE){...}
public DoSomething()
{
Task.Run(async () => {
//some code
repository.ExecuteAsync();
}
}
}
public class Repository : IRepository
{
public Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
return connection.ExecuteAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure, commandTimeout: Configuration.TransactionTimeout);
}
}
}
[Test]
public void TestMethod()
{
var repository = new Mock<IRepository>;
var classToTest = new ClassToTest();
classToTest.DoSomething();
repository.Veryfy(p => p.ExecuteAsync(), Times.Once());
}
The test fails with this message
Expected invocation on the mock once, but was 0 times: p => p.ExecuteAsync()
Does anyone knows why?
Thanks
As others have alluded, because you're calling Task.Run and not waiting for a response, the Unit test will likely complete before the background task is even started, hence the Moq Verify failure.
Also, your code won't compile as is - when asking a Q on StackOverflow, be sure to give a complete, compilable MVP.
Of special importance is the bug in the code you are trying to test. Repository.ExecuteAsync calls connection.ExecuteAsync, inside a using scope, but this isn't awaited. This will mean that the connection will be disposed before the task completes. You'll need to change the method to async and await the call to defer disposal of the connection.
The wrapper method DoSomething method shouldn't use Task.Run(), although, because it adds no value to the repository Task, it doesn't need to repeat the async / return await, either.
The caller (your Unit test, in this instance) can then await DoSomething (or if the caller genuinely wants to do further processing without awaiting the Task, then leave it to the caller to decide. At least this way, the caller gets a handle to the Task, to check on completion).
The final state of your code might look more like this:
public class ClassToTest
{
private readonly IRepository _repository;
public ClassToTest(IRepository repository)
{
_repository = repository;
}
// Doesn't necessarily need to be async
public Task DoSomething()
{
// We're return the wrapped task directly, and adding no additional value.
return repository.ExecuteAsync();
}
}
public class Repository : IRepository
{
public async Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
// Here we do need to await, otherwise we'll dispose the connection
return await connection.ExecuteAsync(storedProcedure, parameters,
commandType: CommandType.StoredProcedure,
commandTimeout: Configuration.TransactionTimeout);
}
}
}
// NUnit has full support for async / await
[Test]
public async Task TestMethod()
{
var repository = new Mock<IRepository>();
var classToTest = new ClassToTest(repository.Object);
repository.Setup(_ => _.ExecuteAsync()).Returns(Task.FromResult((object)null));
// Moq also has support for async, e.g. .ReturnsAsync
// You need to await the test.
await classToTest.DoSomething();
repository.Verify(p => p.ExecuteAsync(), Times.Once());
}
I have a situation where I need to call a web service and, on successful completion, do multiple things with the results returned from the web service. I have developed code that "works" -- just not as I intended. Specifically, I want to take the results from the call to the web service and pass those results onto multiple successive tasks that are to execute in parallel, but what I have at the moment executes the first successive task before starting the second.
I've put together a much simplified example of what I'm currently doing that'll hopefully help illustrate this situation. First, the implementation:
public interface IConfigurationSettings
{
int? ConfigurationSetting { get; set; }
}
public interface IPrintCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface ISaveCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface IWebService
{
System.Threading.Tasks.Task<object> RetrieveReportAsync(string searchToken, string reportFormat);
}
public class ReportCommandHandler
{
private readonly IConfigurationSettings _configurationSettings;
private readonly IPrintCommandHandler _printCommandHandler;
private readonly ISaveCommandHandler _saveCommandHandler;
private readonly IWebService _webService;
public ReportCommandHandler(IWebService webService, IPrintCommandHandler printCommandHandler, ISaveCommandHandler saveCommandHandler, IConfigurationSettings configurationSettings)
{
_webService = webService;
_printCommandHandler = printCommandHandler;
_saveCommandHandler = saveCommandHandler;
_configurationSettings = configurationSettings;
}
public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTask = _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = await reportTask.ContinueWith(task => _printCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = await reportTask.ContinueWith(task => _saveCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(true, (current, result) => current & result);
}
}
So, the web service (third party, nothing to do with me) has an endpoint for doing a search/lookup that, if successful, returns a reference number (I've called it a search token in my example). This reference number is then used to retrieve the results of the lookup (using a different endpoint) in any of several different formats.
The IWebService interface in this example is representative of an application service I created to manage interaction with the web service. The actual implementation has other methods on it for doing a lookup, ping, etc.
Just to make things more interesting, one of the successive tasks is required (will always execute after the primary task) but the other successive task is optional, execution subject to a configuration setting set elsewhere in the application.
To more easily demonstrate the issue, I created a unit test:
public class RhinoMockRepository : IDisposable
{
private readonly ArrayList _mockObjectRepository;
public RhinoMockRepository()
{
_mockObjectRepository = new ArrayList();
}
public T CreateMock<T>() where T : class
{
var mock = MockRepository.GenerateMock<T>();
_mockObjectRepository.Add(mock);
return mock;
}
public T CreateStub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
public void Dispose()
{
foreach (var obj in _mockObjectRepository) obj.VerifyAllExpectations();
_mockObjectRepository.Clear();
}
}
[TestFixture]
public class TapTest
{
private const string SearchToken = "F71C8B50-ECD1-4C02-AD3F-6C24F1AF3D9A";
[Test]
public void ReportCommandExecutesPrintAndSave()
{
using (var repository = new RhinoMockRepository())
{
// Arrange
const string reportContent = "This is a PDF file.";
var reportContentBytes = System.Text.Encoding.Default.GetBytes(reportContent);
var retrieveReportResult = System.Threading.Tasks.Task.FromResult<object>(reportContentBytes);
var webServiceMock = repository.CreateMock<IWebService>();
webServiceMock.Stub(x => x.RetrieveReportAsync(SearchToken, "PDF")).Return(retrieveReportResult);
var printCommandHandlerMock = repository.CreateMock<IPrintCommandHandler>();
var printResult = System.Threading.Tasks.Task.FromResult(true);
printCommandHandlerMock
.Expect(x => x.ExecuteAsync(reportContentBytes))
//.WhenCalled(method => System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2)))
.Return(printResult);
var configurationSettingsStub = repository.CreateStub<IConfigurationSettings>();
configurationSettingsStub.ConfigurationSetting = 10;
var saveCommandHandlerMock = repository.CreateMock<ISaveCommandHandler>();
var saveResult = System.Threading.Tasks.Task.FromResult(true);
saveCommandHandlerMock.Expect(x => x.ExecuteAsync(reportContentBytes)).Return(saveResult);
// Act
var reportCommandHandler = new ReportCommandHandler(webServiceMock, printCommandHandlerMock, saveCommandHandlerMock, configurationSettingsStub);
var result = System.Threading.Tasks.Task
.Run(async () => await reportCommandHandler.ExecuteAsync(SearchToken))
.Result;
// Assert
Assert.That(result, Is.True);
}
}
}
Ideally, on completion of the call to RetrieveReportAsync() on IWebService both the "print" and "save" command handlers should be executed simultaneously, having received a copy of the results from RetrieveReportAsync(). However, if the call to WhenCalled... in the unit test is uncommented, and on stepping through the implementation of ReportCommandHandler.ExecuteAsync(), you can see that the "print" command executes and completes before it gets to the "save" command. Now, I am aware that the whole point of await is to suspend execution of the calling async method until the awaited code completes, but it isn't clear to me how to instantiate both the "print" and "save" commands (tasks) as continuations of the "report" task such that they both execute in parallel when the "report" task completes, and the "report" command is then able to return a result that is based on the results from both the "print" and "save" commands (tasks).
Your question really involves addressing two different goals:
How to wait for a task?
How to execute two other tasks concurrently?
I find the mixing of await and ContinueWith() in your code confusing. It's not clear to me why you did that. One of the key things await does for you is to automatically set up a continuation, so you don't have to call ContinueWith() explicitly. Yet, you do anyway.
On the assumption that's simply a mistake, out of lack of full understanding of how to accomplish your goal, here's how I'd have written your method:
public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTaskResult = await _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = _printCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = _saveCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(false, (current, result) => current | result);
}
In other words, do await the original task first. Then you know it's done and have its result. At that time, go ahead and start the other tasks, adding their Task object to your list, but not awaiting each one individually. Finally, await the entire list of tasks.
I am using Moq to write a unit test. I have a DataManager object which calls WCF to fetch data. I inject this into my controller. however inside the controller the call to the Method in this DataManager is wrapped inside of a Task
System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
}
I have created a mock for the DataManager.GetMyDataObject with Moq
but whenever it is called from this statement inside of the controller method
it returns null. I have googled alot but most of the stuff out there are dealing with methods which have Task as the return signature.
The DataManager.GetMyDataObject is written as standard sync code.
I am using Moq v4.0.10827 and doubt I can upgrade.
I am trying many ways..Moq seems to expect the return to match the method signature
_mockDataManager = new Mock<_mockDataManager>();
_mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()))
and well then returns? I also trid callback
_mockDataManager.Setup(m => System.Threading.Tasks.Task.FromResult(m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>())
.Returns(System.Threading.Tasks.Task.FromResult(myData))
.Callback<MyDataObject>(o => myData = o);
myData = GetMyDataObject();
_mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()).Returns(GetMyDataObject())
private GetMyDataObject() {
returns new DataSet(); //basically an empty dataset but not null
}
Given the following classes:
public class MyDataObject { }
public class UserObj { }
public class DataManager
{
public virtual MyDataObject GetMyDataObject(UserObj userObj, Guid guid)
{
throw new NotImplementedException();
}
}
class SUT
{
public DataManager DataManager { get; private set; }
public SUT(DataManager dataManager)
{
DataManager = dataManager;
}
public void Method(UserObj userobj, Guid recordid)
{
var t = System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
});
t.Wait();
}
}
the following mock works fine:
var mockDataManager = new Mock<DataManager>();
mockDataManager.Setup(m => m.GetMyDataObject(It.IsAny<UserObj>(), It.IsAny<Guid>()));
var sut = new SUT(mockDataManager.Object);
sut.Method(new UserObj(), Guid.Empty);
mockDataManager.VerifyAll();
Two pitfalls:
In the code you posted, you use
_mockDataManager = new Mock<_mockDataManager>();
which should be
_mockDataManager = new Mock<DataManager>(); // or whatever the name of the class is
Maybe this is just a copy/paste error, maybe not.
Also, since you use a Task here:
System.Threading.Tasks.Task.Factory.StartNew<MyDataObject>(()=>
{
return DataManager.GetMyDataObject(userobj, recordid);
}
which calls GetMyDataObject on DataManager, you have to make sure that the Task finished before you verify your mock setup. If you would remove the t.Wait(); from my code above, the test would fail, because VerifyAll would be called before the Task would start and call GetMyDataObject in the mocked object.
I am trying to discover how to apply the async and await keywords to my xUnit tests. I am using xUnit 1.9 and Async CTP 1.3. Here is my test case
I have an interface which specifies one asynchronous method call
public interface IDoStuffAsync
{
Task AnAsyncMethod(string value);
}
I have a class which consumes the interface and calls the async method
public class UseAnAsyncThing
{
private readonly IDoStuffAsync _doStuffAsync;
public UseAnAsyncThing(IDoStuffAsync doStuffAsync)
{
_doStuffAsync = doStuffAsync;
}
public async Task DoThatAsyncOperation(string theValue)
{
await _doStuffAsync.AnAsyncMethod(theValue);
}
}
In my tests I wish to check that the method DoThatAsyncOperation is calling the method with the correct value so I mock the interface and use the Moq to verify the call
[Fact]
public async void The_test_will_pass_even_though_it_should_fail()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));
await sut.DoThatAsyncOperation("test");
// This won't throw a Moq.MockExcpetion so the test appears to pass
// However it does not run
mock.Verify(x => x.AnAsyncMethod("fail"));
}
This test is using the async and await keywords. When it runs it erroneously passes as Moq should assert that the verify fails. Any code after the call to sut.DoThatAsyncOperation("test"); does not run
[Fact]
public void This_will_work_and_assert_the_reslt()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>()));
sut.DoThatAsyncOperation("test").ContinueWith(y => { });
// This won't throw a Moq.MockExcpetion so the test appears to pass
// However it does not run
mock.Verify(x => x.AnAsyncMethod("fail"));
}
This test is setup without the await and async keywords and passes fine.
Is this expected behavior for xUnit and Moq?
Update
Thanks for Stephen's comment I managed to fix the first test by making two changes. The test now returns a Task instead of void and the Mock also returns a Task.
[Fact]
public async Task The_test_will_pass_even_though_it_should_fail()
{
var mock = new Mock<IDoStuffAsync>();
var sut = new UseAnAsyncThing(mock.Object);
mock.Setup(x => x.AnAsyncMethod(It.IsAny<string>())).ReturnAsync(true);
await sut.DoThatAsyncOperation("test");
// This now fails as it should
mock.Verify(x => x.AnAsyncMethod("fail"));
}
Change your unit test method to return Task instead of void, and it should work. Support for async void unit tests is being considered for a future release.
I describe in detail why async unit tests don't work by default on my blog. (My blog examples use MSTest, but the same problems existed in every other test runner, including xUnit pre-1.9).
I tried to use the code from your 'Update', but it was stopping at the async method that I was mocking.
var tcs = new TaskCompletionSource<T>();
tcs.SetResult(default(T));
mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(tcs.Task);
So to fix that I had to change the 'Return' method:
mock.Setup(x => x.AnAsyncMethod(It.IsAny<T>())).Returns(()=> { return tcs.Task; } );