I want to unit test a method that calls another method of a service returning an IAsyncEnumerable<T>.
I have created a a mock of my service Mock<MyService> and I want to setUp this mock but I don't know how to do that. Is it possible ? Are there other ways of unit testing a method that calls something retuning an IAsyncEnumerable
public async Task<List<String>> MyMethodIWantToTest()
{
var results = new List<string>();
await foreach(var item in _myService.CallSomethingReturningAsyncStream())
{
results.Add(item);
}
return results;
}
I recommend using ToAsyncEnumerable from System.Linq.Async, as Jeroen suggested. It seems like you're using Moq, so this would look like:
async Task MyTest()
{
var mock = new Mock<MyService>();
var mockData = new[] { "first", "second" };
mock.Setup(x => x.CallSomethingReturningAsyncStream()).Returns(mockData.ToAsyncEnumerable());
var sut = new SystemUnderTest(mock.Object);
var result = await sut.MyMethodIWantToTest();
// TODO: verify `result`
}
If you don’t want to do anything special, e.g. a delayed return which is usually the point of async enumerables, then you can just create a generator function that returns the values for you.
public static async IAsyncEnumerable<string> GetTestValues()
{
yield return "foo";
yield return "bar";
await Task.CompletedTask; // to make the compiler warning go away
}
With that, you can simply create a mock for your service and test your object:
var serviceMock = new Mock<IMyService>();
serviceMock.Setup(s => s.CallSomethingReturningAsyncStream()).Returns(GetTestValues);
var thing = new Thing(serviceMock.Object);
var result = await thing.MyMethodIWantToTest();
Assert.Equal("foo", result[0]);
Assert.Equal("bar", result[1]);
Of course, since you are now using a generator function, you can also make this more complicated and add actual delays, or even include some mechanism to control the yielding.
It really depends on which mocking framework your using. But, it would be something simple like this example using Moq
var data = new [] {1,2,3,4};
var mockSvc = new Mock<MyService>();
mockSvc.Setup(obj => obj.CallSomethingReturningAsyncStream()).Returns(data.ToAsyncEnumerable());
One way of solving this is to use dedicated test classes that wrap an IEnumerable that is enumerated synchronously.
TestAsyncEnumerable.cs
internal class TestAsyncEnumerable<T> : List<T>, IAsyncEnumerable<T>
{
public TestAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new TestAsyncEnumerator<T>(GetEnumerator());
}
internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(_inner.MoveNext());
public T Current => _inner.Current;
public ValueTask DisposeAsync()
{
_inner.Dispose();
return new ValueTask(Task.CompletedTask);
}
}
Usage:
[Fact]
public async Task MyTest() {
var myItemRepository = A.Fake<IMyItemRepository>();
A.CallTo( () => myRepository.GetAll())
.ReturnsLazily(() => new TestAsyncEnumerable<MyItem>(new List<MyItem> { new MyItem(), ... }));
//////////////////
/// ACT & ASSERT
////////
}
Related
I use MS-Test, moq 4.18.2 and FileSystem (System.IO.Abstractions) 17.0.24 for my tests.
I think I wrote a correct test for InfoLoader_LoadInfoAsync. But, I don't understand how to write a test for MyViewModel::StartLoadInfoAsync to check that InfoList was populated correctly. It seems that I have to duplicate instantiation and configuration of InfoLoader as I did in InfoLoader_LoadInfoAsync. Is there a way around this? How such things are usually tested?
public abstract class IInfoLoader
{
public event Action<MyInfo> InfoLoaded;
public abstract Task LoadInfoAsync();
protected void OnInfoLoaded(MyInfo info)
{
InfoLoaded?.Invoke(info);
}
}
public class InfoLoader : IInfoLoader
{
private readonly IFileSystem _fileSystem;
private readonly string _path;
public InfoLoader(string path, IFileSystem fileSystem) {...}
public async override Task LoadInfoAsync()
{
foreach (var data in await _fileSystem.File.ReadAllLinesAsync(_path))
OnInfoLoaded(new MyInfo(...));
}
}
public class MyViewModel
{
private IInfoLoader _infoLoader;
public ObservableCollection<MyInfo> InfoList { get; }
public MyViewModel(IInfoLoader infoLoader) { ... }
public Task StartLoadInfoAsync()
{
_infoLoader.InfoLoaded += (info) => InfoList.Add(info);
return _infoLoader.LoadInfoAsync();
}
}
Tests
[TestMethod]
public async Task InfoLoader_LoadInfoAsync_Success()
{
var path = "...";
var lines = new string[] { "name1", "name2" };
var expectedInfoList = new List<MyInfo>();
foreach(var line in lines)
expectedInfoList.Add(new MyInfo(line));
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(fs => fs.File.ReadAllLinesAsync(path, CancellationToken.None))
.ReturnsAsync(lines);
var actualInfoList = new List<MyInfo>();
var infoLoader = new InfoLoader(path, fileSystem.Object);
infoLoader.InfoLoaded += (info) => actualInfoList.Add(info);
await infoLoader.LoadInfoAsync();
// Assert that items in expectedInfoList and actualInfoList are equal
}
[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success()
{
var expectedInfoList = new List<MyInfo>();
// WHAT DO I DO HERE? DO I CREATE AND CONFIGURE infoLoader LIKE in "InfoLoader_LoadInfoAsync" TEST?
var vm = new MyViewModel(infoLoader.Object);
await vm.StartLoadInfoAsync();
actualInfoList = vm.InfoList;
// Assert that items in expectedInfoList and actualInfoList are equal
}
Since the view model depends on the IInfoLoader abstraction, it can be mocked to behave as expected when the desired member is invoked.
Review the comments in the following example
[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success() {
//Arrange
var info = new MyInfo();
List<MyInfo> expectedInfoList = new List<MyInfo>() { info };
// WHAT DO I DO HERE?
var dependency = new Mock<IInfoLoader>(); //mock the dependency
dependency
// When LoadInfoAsync is invoked
.Setup(_ => _.LoadInfoAsync())
// Use callback to raise event passing the custom arguments expected by the event delegate
.Callback(() => dependency.Raise(_ => _.InfoLoaded += null, info))
// Then allow await LoadInfoAsync to complete properly
.Returns(Task.CompletedTask);
MyViewModel subject = new MyViewModel(dependency.Object);
//Act
await subject.StartLoadInfoAsync();
//Assert
List<MyInfo> actualInfoList = subject.InfoList;
actualInfoList.Should().NotBeEmpty()
And.BeEquivalentTo(expectedInfoList); //Using FluentAssertions
}
Note how a Callback is used to capture when LoadInfoAsync is invoked by the subject so that an event can be raised by the mock, allowing the subject under test to flow to completion as desired
Reference MOQ Quickstart: Events
In order to test StartLoadInfoAsync you need an instance of MyViewModel, so you should:
Create this instance.
Invoke the method StartLoadInfoAsync.
Assert that its state is according to what you need.
Now obviously you have a dependency, which is InfoLoader, so you have two options:
Create and configure a new instance of InfoLoader
Mock InfoLoader so you can test MyViewModel independently of InfoLoader.
The second approach is what you may want to follow, this way you do not need to configure again InfoLoader, mock the FileSystem and so on.
You only need to create a mock of InfoLoader and setup its calls, just like you did with the FileSystem.
I have a class with few methods. For these methods, I'm creating Unit Test cases using MSTest.
public class Class1
{
public virtual async Task<bool> GetData()
{
string var1 ="dsfs", var2 ="eer";
bool retVal = await DoSomething(var1, var2);
// some business logic
return true;
}
public virtual async Task<bool> DoSomething(string var1, string var2)
{
return true;
}
}
The test cases for method GetData() looks like this.
[TestClass()]
public class Class1Test
{
[TestMethod()]
public async Task GetDataTest()
{
var mockService = new Mock<Class1>();
var isTrue = ReturnTrue(); // this function returns true
mockService.Setup(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>())).Returns(isTrue);
var result = await mockService.Object.GetData();
Assert.IsTrue(result);
}
}
Now, the problem I'm facing is,
var result = await mockService.Object.GetData();
From this line the control doesn't go to the actual GetData() method in Class1. If I remove virtual keyword from the method definition, then the control goes to the method, i.e, if I make the method like this.
public async Task<bool> GetData()
{
bool retVal = await DoSomething(var1, var2);
// some business logic
return true;
}
I need to make this method virtual because, this method is called in some other method say "XYZMethod" and for writing test case "XYZMethod", I had mocked GetData() method there.
So is there anyway I can solve this problem without removing virtual keyword.
PS: Writing interfaces is not an option as this is a very heavy code which I'm working on and introducing Interface at this stage is not practical.
Enable CallBase on the mock so that it will invoke base members that have not been overridden by a setup expectation.
Also use ReturnsAsync when configuring asynchronous mocked members to allow them to flow correctly when invoked.
[TestClass()]
public class Class1Test {
[TestMethod()]
public async Task GetDataTest() {
//Arrange
var mockService = new Mock<Class1>(){
CallBase = true
};
var expected = ReturnTrue(); // this function returns true
mockService
.Setup(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(expected);
//Act
var actual = await mockService.Object.GetData();
//Assert
Assert.IsTrue(actual);
}
}
I'm a bit confused about the usage of ReactiveTest: https://msdn.microsoft.com/en-us/library/hh242967%28v=vs.103%29.aspx
I have a method ScanDevices in a class DeviceService that I'd like to test with the ReactiveTest features.
The method takes an IObservable from bleAdapter.Scan().
I'd like to mock this bleAdapter.Scan(), to unit test the behavior of ScanDevices() . I try to mock the bleAdapter.Scan() with Moq.
//interface to mock
public interface IAdapter {
IObservable<IScanResult> Scan(ScanConfig config = null);
}
//class to test
class DeviceService {
public IObservable<DeviceModel> ScanDevices()
{
return bleAdapter.Scan() // this returns an IObservable
.Where(IsMatching)
.Distinct(DistinctByUuid)
.Select(ToDeviceModel);
}
}
Here is my unit test:
public class DeviceServiceTest: ReactiveTest {
[TestMethod]
public void ShouldReceiveOneDevice()
{
var mockBleAdapter = new Mock<IAdapter>();
var deviceInteractionService = new DeviceInteractionService(mockBleAdapter.Object);
var scheduler = new TestScheduler();
var obs = scheduler.CreateColdObservable(OnNext(100, new MockScannedDevice())); // create an observable that will emit one value
mockBleAdapter.Setup(adapter => adapter.Scan(null))
.Returns(obs); // use Moq framework to return the observable created
scheduler.Start();
deviceInteractionService.ScanDevices()
.Subscribe(res => Console.WriteLine("hello"));
}
}
The "hello" is never printed. I'm doing it wrong...
Do you have any good way to do it?
Thanks
Argh... the issue was that you need to setup your subscriptions before calling scheduler.Start()
So, to get the hello to be printed, here it is:
public class DeviceServiceTest: ReactiveTest {
[TestMethod]
public void ShouldReceiveOneDevice()
{
var mockBleAdapter = new Mock<IAdapter>();
var deviceInteractionService = new DeviceInteractionService(mockBleAdapter.Object);
var scheduler = new TestScheduler();
var obs = scheduler.CreateColdObservable(OnNext(100, new MockScannedDevice())); // create an observable that will emit one value
mockBleAdapter.Setup(adapter => adapter.Scan(null))
.Returns(obs); // use Moq framework to return the observable created
// subscribe
deviceInteractionService.ScanDevices()
.Subscribe(res => Console.WriteLine("hello"));
// then start
scheduler.Start();
}
}
I'm slowly starting to get the hang of unit-testing and mocking, but it's a slow process. I have tried unit testing this Active Directory code. The question is not strictly relevant to AD.
class ActiveDirectoryQueryer {
DirectorySearcher mSearcher;
public ActiveDirectoryQueryer() {
var searcher = new DirectorySearcher(...);
}
public void GetAllMailEntries() {
MailEntries =
mSearcher
.FindAll()
.Select(result => result.GetDirectoryEntry())
.Select(BuildNewADUser)
.ToList();
}
static ActiveDirectoryUser BuildNewADUser(DirectoryEntry pDirectoryEntry) {
return ActiveDirectoryUser.Create(
pDirectoryEntry.Guid,
(pDirectoryEntry.Properties["name"].Value ?? "").ToString(),
(pDirectoryEntry.Properties["mail"].Value ?? "").ToString()
);
}
So, I would like to unit test the GetAllMailEntries method. In order to do this using MOQ I've had to manually generate interfaces and wrappers for various .NET types, and changed many of the above references to interfaces instead (like IDirectoryEntry). Each of the IXxxx interfaces below has an associated wrapper class XxxxWrapper. In total I added at least 12 new source files just for this one test. Here's what I've ended up with for the unit test:
[TestMethod]
public void TestGetAllMailEntries() {
var mockSearcher = new Mock<IDirectorySearcher>();
var mockResultCollection = new Mock<ISearchResultCollection>();
var mockSearchResult = new Mock<ISearchResult>();
var mockDirectoryEntry = new Mock<IDirectoryEntry>();
var mockPropertyCollection = new Mock<IPropertyCollection>();
var nameMockPropertyValueCollection = new Mock<IPropertyValueCollection>();
var mailMockPropertyValueCollection = new Mock<IPropertyValueCollection>();
const string name = "SomeNameValue";
const string mailAddress = "SomeMailAddress";
nameMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(name);
mailMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(mailAddress);
mockPropertyCollection.SetupGet(pc => pc["name"]).Returns(nameMockPropertyValueCollection.Object);
mockPropertyCollection.SetupGet(pc => pc["mail"]).Returns(mailMockPropertyValueCollection.Object);
mockDirectoryEntry.SetupGet(de => de.Properties).Returns(mockPropertyCollection.Object);
mockSearchResult.Setup(sr => sr.GetDirectoryEntry()).Returns(mockDirectoryEntry.Object);
mockResultCollection.Setup(results => results.GetEnumerator()).Returns(new List<ISearchResult> { mockSearchResult.Object }.GetEnumerator());
mockSearcher.Setup(searcher => searcher.FindAll()).Returns(mockResultCollection.Object);
var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
queryer.GetAllMailEntries();
Assert.AreEqual(1, queryer.MailEntries.Count());
var entry = queryer.MailEntries.Single();
Assert.AreEqual(name, entry.Name);
Assert.AreEqual(mailAddress, entry.EmailAddress);
}
Is it normal to have this many interfaces and wrapper classes? (The wrappers are necessary since .NET types cannot otherwise implement my interfaces.)
I think my problem is mirroring the .NET structure too closely. I shouldn't wrap each and every .NET type all the way down till I get to just primitives. Rather, I should take the first opportunity to remove all dependencies as soon as I can. In this case it's with the DirectorySearcher class, and the FindAll method.
DirectorySearcher.FindAll returns a SearchResultCollection, but rather than thinking of my "wrapper" class as just an adapter to the .NET type, I should make more use of it.
Ignoring the implementation of IDisposable and other unnecessary code, my wrapper had looked like this:
public interface IDirectorySearcher : IDisposable {
ISearchResultCollection FindAll();
}
class DirectorySearcherWrapper : IDirectorySearcher {
DirectorySearcher mDirectorySearcher;
DirectorySearcherWrapper(DirectorySearcher pDirectorySearcher) {
mDirectorySearcher = pDirectorySearcher;
}
public static IDirectorySearcher Wrap(DirectorySearcher pDirectorySearcher) {
return new DirectorySearcherWrapper(pDirectorySearcher);
}
public ISearchResultCollection FindAll() {
return SearchResultCollectionWrapper.Wrap(mDirectorySearcher.FindAll());
}
}
Rather, I should take the opportunity to stop all dependencies right here. I don't have to return a .NET type or even just a wrapper to a .NET type, I can now use this interface to return whatever I want. IE: If what I want to get from the FindAll method is a bunch of ActiveDirectoryUsers, then return just that.
My code then becomes:
public interface IDirectorySearcher : IDisposable {
IEnumerable<ActiveDirectoryUser> FindAll();
}
class DirectorySearcherWrapper : IDirectorySearcher {
DirectorySearcher mDirectorySearcher;
DirectorySearcherWrapper(DirectorySearcher pDirectorySearcher) {
mDirectorySearcher = pDirectorySearcher;
}
public static IDirectorySearcher Wrap(DirectorySearcher pDirectorySearcher) {
return new DirectorySearcherWrapper(pDirectorySearcher);
}
public IEnumerable<ActiveDirectoryUser> FindAll() {
return
mDirectorySearcher
.FindAll()
.Cast<SearchResult>()
.Select(result => result.GetDirectoryEntry())
.Select(/*BuildNewADUser*/)
.ToList();
}
}
And the GetAllMailEntries method becomes simply:
public void GetAllMailEntries() {
MailEntries = mSearcher.FindAll();
}
And the unit test becomes:
[TestMethod]
public void TestGetAllMailEntries2() {
var mockSearcher = new Mock<IDirectorySearcher>();
mockSearcher
.Setup(s => s.FindAll())
.Returns(new[] {
ActiveDirectoryUser.Create(new Guid(), "Name", "EmailAddress")
});
var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
queryer.GetAllMailEntries();
Assert.AreEqual(1, queryer.MailEntries.Count());
var entry = queryer.MailEntries.Single();
Assert.AreEqual("Name", entry.Name);
Assert.AreEqual("EmailAddress", entry.EmailAddress);
}
Since I have converted my WCF methods to Async, my unit tests have failed, and I can't figure out the correct syntax to get them to work.
Cllient proxy class
public interface IClientProxy
{
Task DoSomething(CredentialDataList credentialData, string store);
}
service class
public class CredentialSync : ICredentialSync
{
private ICredentialRepository _repository;
private IClientProxy _client;
public CredentialSync()
{
this._repository = new CredentialRepository();
this._client = new ClientProxy();
}
public CredentialSync(ICredentialRepository repository, IClientProxy client)
{
this._repository = repository;
this._client = client;
}
public async Task Synchronise(string payrollNumber)
{
try
{
if (string.IsNullOrEmpty(payrollNumber))
{
.... some code
}
else
{
CredentialDataList credentialData = new CredentialDataList();
List<CredentialData> credentialList = new List<CredentialData>();
// fetch the record from the database
List<GetCredentialData_Result> data = this._repository.GetCredentialData(payrollNumber);
var pinData = this._repository.GetCredentialPinData(payrollNumber);
// get the stores for this employee
var storeList = data.Where(a => a.StoreNumber != null)
.GroupBy(a => a.StoreNumber)
.Select(x => new Store { StoreNumber = x.Key.ToString() }).ToArray();
var credential = this.ExtractCredentialData(data, pinData, payrollNumber);
credentialList.Add(credential);
credentialData.CredentialList = credentialList;
foreach (var store in storeList)
{
//this line causes an Object reference not set to an instance of an object error
await _client.DoSomething(credentialData, store.StoreNumber);
}
}
}
catch (Exception ex)
{
throw new FaultException<Exception>(ex);
}
}
Test Class
/// </summary>
[TestClass]
public class SynchTest
{
private Mock<ICredentialRepository> _mockRepository;
private Mock<IClientProxy> _mockService;
[TestInitialize]
public void Setup()
{
... some setups for repository which work fine
}
[TestMethod]
public async Task SynchroniseData_WithOneEmployee_CallsReplicateService()
{
this._mockService = new Mock<IClientProxy>();
this._mockService.Setup(x=>x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>()));
// arrange
string payrollNumber = "1";
CredentialSync service = new CredentialSync(this._mockRepository.Object, this._mockService.Object);
// act
await service.Synchronise(payrollNumber);
// assert
this._mockService.VerifyAll();
}
The error is when ClientProxy.DoSomething is called:
Object reference not set to an instance of an object
The parameters are both fine.
If I convert my ClientProxy.DoSomething method to a synchronous method
(public void DoSomething(...) )the code works fine, but I do need this to be called asynchronously
DoSomething returns null instead of returning a Task, and so you get an exception when awaiting it. You need to specify when building the mock that it should return a Task.
In this case it seems that you can simply return an already completed task using Task.FromResult so the mock setup should look like this:
this._mockService.Setup(...).Returns(Task.FromResult(false));
Beginning with the next version of .Net (4.6) you can use Task.CompletedTask like this:
this._mockService.Setup(...).Returns(Task.CompletedTask);
You can reduce the amount of clutter in the code by using ReturnsAsync
this._mockService.Setup(...).ReturnsAsync(false);
This way you can remove the Task.FromResult part of the code
I think you need to return the Task from the DoSomething mock
this._mockService.Setup(x => x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>()))
.Returns(Task.FromResult<int>(0));