How to mock StreamReader in NUnit - c#

I am trying to use NUnit and Moq for writing unit tests for my sample project. I have a service class like below:
SentimentService.cs:
public class SentimentService : ISentimentService
{
private readonly IStreamReader _reader;
private readonly IServerClient _serverClient;
public SentimentService(IStreamReader reader, IServerClient serverClient)
{
_reader = reader;
_serverClient = serverClient;
}
public async Task<string> CalculateSentimentFromTextFile(IFormFile file)
{
var input = "";
using (StreamReader streamReader = _reader.GetReader(file.OpenReadStream()))
{
input = streamReader.ReadToEnd();
streamReader.Close();
}
var result = await _serverClient.PostAsync<SentimentResult, string>($"submit_string", input);
return result.label;
}
}
I tried of using Moq like below:
[Test]
public async Task CalculateSentimentFromTextFileEquality()
{
var mockFormFile = new Mock<IFormFile>();
var mockStreamReader = new Mock<IStreamReader>();
var mockServerClient = new Mock<IServerClient>();
var mockResult = new SentimentResult
{
label = "Positive"
};
mockStreamReader.Setup(o => o.GetReader(mockFormFile.Object.OpenReadStream()));
mockServerClient.Setup(o => o.PostAsync<SentimentResult, string>(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(mockResult);
var sut = new SentimentService(mockStreamReader.Object, mockServerClient.Object);
var result = await sut.CalculateSentimentFromTextFile(mockFormFile.Object);
Assert.That(result, Is.EqualTo("Positive"));
}
But, getting the below error:

This setup:
mockStreamReader.Setup(o => o.GetReader(mockFormFile.Object.OpenReadStream()));
does not return any object and thus when calling this in SUT:
StreamReader streamReader = _reader.GetReader(file.OpenReadStream()
will return a null object.
However, StreamReader has parameterless constructors, which means you have to provide the real file path/stream if you want to mock it. One way to handle the StreamReader is to create an interface which later can be implemented by a wrapper of StreamReader.
public interface IStreamReader : IDisposable
{
string ReadToEnd();
void Close();
}
Creation of IStreamReader is made by a factory:
public interface IStreamReaderFactory
{
IStreamReader GetReader(Stream stream);
}
Your SUT can be modified to:
public class SentimentService : ISentimentService
{
private readonly IStreamReaderFactory _readerFactory;
private readonly IServerClient _serverClient;
public SentimentService(IStreamReaderFactory readerFactory, IServerClient serverClient)
{
_readerFactory = readerFactory;
_serverClient = serverClient;
}
public async Task<string> CalculateSentimentFromTextFile(IFormFile file)
{
var input = "";
using (IStreamReader streamReader = _readerFactory.GetReader(file.OpenReadStream()))
{
input = streamReader.ReadToEnd();
streamReader.Close();
}
var result = await _serverClient.PostAsync<SentimentResult, string>($"submit_string", input);
return result.label;
}
}
The test code should now be able to setup IStreamReader properly.
var mockStreamReader = new Mock<IStreamReader>();
var mockStreamReaderFactory = new Mock<IStreamReaderFactory>();
mockStreamReaderFactory.Setup(o => o.GetReader(It.IsAny<Stream>())).Returns(mockStreamReader.Object);

Related

How to access the static method via MOQ in c sharp

I am using mock library in my .Net unit test and getting an error
cannot be accessed with an instance reference instead use type name.
I am getting this error at following line in my test method where it is calling cq.Instance. I am new to mock library. Could somebody let me know how do I call the static method?
attributeValue.Setup(cq => cq.Instance().CallQueryAsync(request, 1)).Returns(attrValue);
Actual method to be tested
public static async Task<AttributeValueList> GetAttributeSecDateValueList(int attrId)
{
try
{
var request = AttributeValue.ResolveRequest(attrId);
var response = await AsyncProxy<AttributeValue>.Instance().CallQueryAsync(request, (int)AttributeValue.OperationType.GetSecDateValues);
var coll = new AttributeValueList();
coll.AddRange(response);
return coll;
}
catch (Exception e)
{
throw e;
}
}
Proxy class
public class AsyncProxy<RT> : IDisposable
where RT : class, new()
{
readonly WebServiceProxy<RT> _wsProxy;
private AsyncProxy(WebServiceProxy<RT> webServiceProxy)
{
_wsProxy = webServiceProxy;
}
public static async Task<IEnumerable<RT>> Load(object parameters)
{
return await Instance().CallQueryAsync(parameters);
}
public static AsyncProxy<RT> Instance()
{
return new AsyncProxy<RT>(WebServiceProxy<RT>.Instance());
}
/// <summary>
/// Return result set of Poco as smartCollection
/// </summary>
public async Task<SmartCollection<RT>> CallQueryAsync(object request, int? uniqueIdentifier = null, bool isLongRunning = false, [CallerMemberName]string memberName = "")
{
//#if DEBUG
// var stopwatch = new Stopwatch();
// stopwatch.Start();
//#endif
try
{
// We want to get rid of the proxy as soon as we are done with it
using (_wsProxy)
{
var awaited = await _wsProxy.CallQueryAsync(request, uniqueIdentifier, isLongRunning);
if (awaited == null)
return null;
var observableCollection = new SmartCollection<RT>();
foreach (var item in awaited)
observableCollection.Add(item as RT);
return observableCollection;
}
}
finally
{
Dispose();
//#if DEBUG
// stopwatch.Stop();
// Debug.WriteLine(null);
// Debug.WriteLine($"****>>>>> AsyncProxy {memberName} took {stopwatch.ElapsedMilliseconds} ms <<<<<<<<****");
//#endif
}
}
}
test method
[TestMethod]
public void test()
{
Task<SmartCollection<AttributeValue>> attrValue = null;
var request = new AttributeValue();
var attributeValue = new Mock<AsyncProxy<AttributeValue>>();
attributeValue.Setup(cq => cq.Instance().CallQueryAsync(request, 1)).Returns(attrValue);
}

How can the FileInfo class be mocked using System.IO.Abstractions?

I have injected the System.IO.Abstractions.IFileSystem interface into a class so that I can unit test file system interactions. There is one place in the class that uses new FileInfo(fileName). What is the replacement for that when using the IFileSystem interface and MockFileSystem?
Replacing File.OpenRead with _fileSystem.File.OpenRead is simple...
public string? Decrypt(string encryptedFilePath, string privateKeyArmor, string passPhrase)
{
try
{
using var privateKeyStream = new MemoryStream(Encoding.ASCII.GetBytes(privateKeyArmor));
using var encryptedFileStream = _fileSystem.File.OpenRead(encryptedFilePath);
var inputStream = PgpUtilities.GetDecoderStream(encryptedFileStream);
...
...but I don't know how to replace new FileInfo(fileName) here.
private byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
{
var outputStream = new MemoryStream();
var compressedDataGen = new PgpCompressedDataGenerator(algorithm);
PgpUtilities.WriteFileToLiteralData(compressedDataGen.Open(outputStream), PgpLiteralData.Binary,
new FileInfo(fileName));
...
I tried _fileSystem.FileInfo.FromFileName(fileName), but that returns IFileInfo instead of FileInfo and the WriteFileToLiteralData method won't take that.
There is a helper function FileInfo.New(string fileName) which can be used to create/use a mock IFileInfo object
public class FileInfoTest
{
private readonly IFileSystem _fileSystem;
public FileInfoTest()
: this (new FileSystem())
{
}
internal FileInfoTest(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public bool GetIsReadOnly(string path)
{
var info = _fileSystem.FileInfo.New(path);
return info.IsReadOnly;
}
}
To demonstrate this I have a physical file which is not read-only.
The first test, returns the IsReadonly state of the physical file.
The second, returns a mocked IFileInfo object with IsReadOnly set to true.
[TestMethod]
public void CheckFileInfoAgainstPhysicalFile()
{
var tester = new FileInfoTest();
var isReadOnly = tester.GetIsReadOnly(#"c:\dev\File.txt");
Assert.IsFalse(isReadOnly);
}
[TestMethod]
public void CheckFileInfoAgainstMock()
{
var mockFileInfo = new Mock<IFileInfo>();
mockFileInfo.SetupGet(mk => mk.IsReadOnly).Returns(true);
var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(mk => mk.FileInfo.New(#"c:\dev\File.txt")).Returns(mockFileInfo.Object);
var tester = new FileInfoTest(mockFileSystem.Object);
var isReadOnly = tester.GetIsReadOnly(#"c:\dev\File.txt");
Assert.IsTrue(isReadOnly);
}
As mentioned in the comment, the above doesn't address the basic problem - PgpUtilities doesn't know what an IFileInfo is.
There is a way to fix this but it may not be worth the effort.
Define an interface for the methods used from the static class.
Inject this interface.
In the default implementation of `IPgpUtilities`, use reflection to get at the `FileInfo` instance inside the `FileInfoWrapper` and pass it through to the external routine.
// Stand-in for External utility (returns a string so we can see it
// doing something with the original file)
public static class PgpUtilitiesOriginal
{
public static string WriteFileToLiteralData(Stream outputStream,
char fileType,
FileInfo file)
{
return file.Name;
}
}
// Interface for injection
public interface IPgpUtilties
{
string WriteFileToLiteralData(Stream outputStream,
char fileType,
IFileInfo file);
}
// Wrapper for the External Utility
public class DefaultPgpUtilities : IPgpUtilties
{
public string WriteFileToLiteralData(Stream outputStream, char fileType, IFileInfo file)
{
var instanceInfo = file.GetType().GetField("instance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var instance = (FileInfo)instanceInfo.GetValue(file);
return PgpUtilitiesOriginal.WriteFileToLiteralData(outputStream, fileType, instance);
}
}
// Test Target
public class Tester
{
private readonly IFileSystem _fileSystem;
private readonly IPgpUtilties _pgpUtilities;
public Tester()
: this(new FileSystem(), new DefaultPgpUtilities())
{
}
public Tester(IFileSystem fileSystem, IPgpUtilties pgpUtilities)
{
_fileSystem = fileSystem;
_pgpUtilities = pgpUtilities;
}
public string Run(string fileName)
{
return _pgpUtilities.WriteFileToLiteralData(null, '\0', _fileSystem.FileInfo.FromFileName(fileName));
}
}
[TestMethod]
public void PhysicalFile()
{
var tester = new Tester();
var ret = tester.Run(#"c:\dev\file.txt");
Assert.AreEqual("file.txt", ret);
}
[TestMethod]
public void MockedFile()
{
var mockFileObject = new Mock<IFileInfo>();
var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(mk => mk.FileInfo.FromFileName(#"c:\dev\file.txt")).Returns(mockFileObject.Object);
var mockPgpUtilties = new Mock<IPgpUtilties>();
mockPgpUtilties.Setup(mk => mk.WriteFileToLiteralData(It.IsAny<Stream>(), It.IsAny<char>(), mockFileObject.Object)).Returns("Hello World");
var tester = new Tester(mockFileSystem.Object, mockPgpUtilties.Object);
var ret= tester.Run(#"c:\dev\file.txt");
Assert.AreEqual("Hello World", ret);
}
Again, sorry about the piss-poor reading of the original question on my part.

How to write repository unit tests with respect to Cosmos database(SQLApi + CosmosClient)

I have a class as below :
public class CosmosRepository: ICosmosRepository
{
private ICosmoDBSettings cosmoDbSettings;
private CosmosClient cosmosClient;
private static readonly object syncLock = new object();
// The database we will create
private Database database;
public CosmosRepository(ICosmoDBSettings cosmoDBSettings)
{
this.cosmoDbSettings = cosmoDBSettings;
this.InitializeComponents();
}
private void InitializeComponents()
{
try
{
if (cosmosClient != null)
{
return;
}
lock (syncLock)
{
if (cosmosClient != null)
{
return;
}
this.cosmosClient = new CosmosClient(
cosmoDbSettings.CosmosDbUri
, cosmoDbSettings.CosmosDbAuthKey
, new CosmosClientOptions
{
ConnectionMode = ConnectionMode.Direct
}
);
this.database = this.cosmosClient.CreateDatabaseIfNotExistsAsync(cosmoDbSettings.DocumentDbDataBaseName).Result;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
I have my repository method as:
Don't bother about hardcoded values.
public async Task<Employee> GetById()
{
var container = this.database.GetContainer("Employees");
var document = await container.ReadItemAsync<Employee>("44A85B9E-2522-4BDB-891A-
9EA91F6D4CBF", new PartitionKey("PartitionKeyValue"));
return document.Response;
}
Note
How to write Unit Test(MS Unit tests) in .NET Core with respect to Cosmos Database?
How to mock CosmosClient and all its methods.
Could someone help me with this issue?
My UnitTests looks like:
public class UnitTest1
{
private Mock<ICosmoDBSettings> cosmoDbSettings;
private Mock<CosmosClient> cosmosClient;
private Mock<Database> database;
[TestMethod]
public async Task TestMethod()
{
this.CreateSubject();
var databaseResponse = new Mock<DatabaseResponse>();
var helper = new CosmosDBHelper(this.cosmoDbSettings.Object);
this.cosmosClient.Setup(d => d.CreateDatabaseIfNotExistsAsync("TestDatabase", It.IsAny<int>(), It.IsAny<RequestOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(databaseResponse.Object);
var mockContainer = new Mock<Container>();
this.database.Setup(x => x.GetContainer(It.IsAny<string>())).Returns(mockContainer.Object);
var mockItemResponse = new Mock<ItemResponse<PortalAccount>>();
mockItemResponse.Setup(x => x.StatusCode).Returns(It.IsAny<HttpStatusCode>);
var mockPortalAccount = new PortalAccount { PortalAccountGuid = Guid.NewGuid() };
mockItemResponse.Setup(x => x.Resource).Returns(mockPortalAccount);
mockContainer.Setup(c => c.ReadItemAsync<PortalAccount>(It.IsAny<string>(),It.IsAny<PartitionKey>(), It.IsAny<ItemRequestOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(mockItemResponse.Object);
var pas = helper.GetById().Result;
Assert.AreEqual(pas.PortalAccountGuid, mockPortalAccount.PortalAccountGuid);
}
public void CreateSubject(ICosmoDBSettings cosmoDBSettings = null)
{
this.cosmoDbSettings = cosmoDbSettings ?? new Mock<ICosmoDBSettings>();
this.cosmoDbSettings.Setup(x => x.CosmosDbUri).Returns("https://localhost:8085/");
this.cosmoDbSettings.Setup(x => x.CosmosDbAuthKey).Returns("C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==");
this.cosmoDbSettings.Setup(x => x.DocumentDbDataBaseName).Returns("TestDatabase");
this.database = new Mock<Database>();
this.cosmosClient = new Mock<CosmosClient>();
}
}
Note:
Exception:
Response status code does not indicate success: 404 Substatus: 0 Reason: (Microsoft.Azure.Documents.DocumentClientException: Message: {"Errors":["Resource Not Found"]}
I'm not creating a document. directly I'm fetching the document because I'm returning the mock response only. Is it correct??

Moq.Setup Expression of type 'System.Web.Mvc.ActionResult' cannot be used for return type 'System.Web.Mvc.ActionResult'

I'm working on some legacy code (def: untested code - some well designed some not) and trying to develop some tests to confirm recent changes did what they expected etc. I'm running into an issue where I'm trying to force a method that has a try{catch} block in it to throw an exception using Moq. When I try to run the test it fails during the mock.Setup call with System.ArgumentException "Expression of type 'System.Web.Mvc.ActionResult' cannot be used for return type 'System.Web.Mvc.ActionResult'".
The basic setup of the code:
Interface for FilterController...
public interface IFilterController
{
ActionResult DeleteFilter(string reportFilter, bool customReport = true);
}
FilterController class...
public class FilterController : BaseController, IFilterController
{
public FilterController(
IServiceFactory serviceFactory,
IAwsServiceFactory awsServiceFactory,
IReportServiceFactory reportServiceFactory,
IAzureServiceFactory azureServiceFactory)
: base(typeof(FilterController), serviceFactory, awsServiceFactory, reportServiceFactory, azureServiceFactory)
{
}
// method under test
public ActionResult (string reportFilter, bool customReport = true) {
try {
// NOTE: I have trimmed down the actual code in the try block significantly for brevity - I should be able to hook onto something here as a way to mock something throwing an exception
var customReportFilterService = _serviceFactory.CreateCustomReportFilterService();
var emailReportSettingService = _serviceFactory.CreateEmailReportSettingService();
string message = string.Empty;
JsonReturnType type = JsonReturnType.DisplayMessage; // an enum
var filter = customReportFilterService.GetReportFilterByHash(SessionHelper.User.CustomerId, reportFilter, initLinkedProjects: true);
return JsonActionResult(type, ajaxMessage: message, redirectTo: filter == null ? null : string.Format("Report/{0}", filter.ReportName));
}
catch (Exception ex)
{
return JsonActionResult(JsonReturnType.Error, ajaxMessage: "There was an error in deleting the filter.");
}
}
}
BaseController class...
public class BaseController : Controller
{
private readonly ProgressController _progressController;
protected IServiceFactory _serviceFactory;
protected IAwsServiceFactory _awsServiceFactory;
protected IReportServiceFactory _reportServiceFactory;
protected IAzureServiceFactory _azureServiceFactory;
protected IApplicationSettingService _applicationSettingService;
protected IReportMonitorService _reportMonitorService;
protected ISymmetricAlgorithmProvider HiddenEncrypter { get; set; }
private Stopwatch _watch;
private bool _timePageEnabled;
private bool _maintenance;
private int _pageLoadThreshold;
private readonly ILog Logger;
public BaseController(Type type, IServiceFactory serviceFactory, IAwsServiceFactory awsServiceFactory, IReportServiceFactory reportServiceFactory, IAzureServiceFactory azureServiceFactory)
{
Logger = LogManager.GetLogger(type);
_progressController = new ProgressController();
_serviceFactory = serviceFactory;
_awsServiceFactory = awsServiceFactory;
_reportServiceFactory = reportServiceFactory;
_azureServiceFactory = azureServiceFactory;
_applicationSettingService = _serviceFactory.CreateApplicationSettingService();
_reportMonitorService = _serviceFactory.CreateReportMonitorService();
_watch = new Stopwatch();
_timePageEnabled = _applicationSettingService.ReadApplicationSettingFromCache<bool>(CC.Data.Model.Constants.ApplicationSettings.CheckSlowPageLoad, true);
_pageLoadThreshold = _applicationSettingService.ReadApplicationSettingFromCache<int>(CC.Data.Model.Constants.ApplicationSettings.PageLoadThreshold, 120);
_maintenance = _applicationSettingService.MaintenanceMode();
}
// System.Web.Mvc.ActionResult type mentioned in error
public ActionResult JsonActionResult(JsonReturnType returnType, string view = null, string ajaxMessage = null, string redirectTo = null, string target = null, object data = null, string popupTitle = null)
{
if (returnType == JsonReturnType.LoadContent)
_progressController.CompleteProgressCache();
var serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = Int32.MaxValue;
var resultData = new {
ReturnType = returnType,
HtmlView = view,
Message = ajaxMessage,
RedirectTo = redirectTo,
Target = target,
CustomData = data,
ProjectId = SessionHelper.ProjectId,
PopupTitle = popupTitle,
MaintenanceMode = _maintenance
};
ContentResult result;
result = new ContentResult
{
Content = serializer.Serialize(resultData),
ContentType = "application/json"
};
return result;
}
}
Controller class...
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter {
// stuff
}
Unit Test class...
[TestClass]
public class FilterControllerTest
{
private FilterController filterController;
private Mock<IFilterController> filterControllerMock;
private Mock<IServiceFactory> serviceFactoryMock;
private Mock<IAwsServiceFactory> awsServiceFactoryMock;
private Mock<IReportServiceFactory> reportServiceFactoryMock;
private Mock<IAzureServiceFactory> azureServiceFactoryMock;
private Mock<IApplicationSettingService> applicationSettingServiceMock;
[ClassInitialize]
public static void ClassInit(TestContext context)
{
}
[TestInitialize]
public void Initialize()
{
filterControllerMock = new Mock<IFilterController>();
serviceFactoryMock = new Mock<IServiceFactory>();
awsServiceFactoryMock = new Mock<IAwsServiceFactory>();
reportServiceFactoryMock = new Mock<IReportServiceFactory>();
azureServiceFactoryMock = new Mock<IAzureServiceFactory>();
applicationSettingServiceMock = new Mock<IApplicationSettingService>();
serviceFactoryMock
.Setup(s => s.CreateApplicationSettingService())
.Returns(applicationSettingServiceMock.Object);
filterController = new FilterController(
serviceFactoryMock.Object
, awsServiceFactoryMock.Object
, reportServiceFactoryMock.Object
, azureServiceFactoryMock.Object);
}
[TestCleanup]
public void Cleanup()
{
}
[ExpectedException(typeof(Exception))]
[TestMethod]
public void DeleteFilter_ExceptionThrown_IsCaughtAndLoggedAndReturnsActionResultOfError()
{
// Arrange
filterControllerMock
.Setup(x => x.DeleteFilter(It.IsAny<string>(), It.IsAny<bool>()))
.Throws(new Exception());
// Act
var result = filterController.DeleteFilter("myfilt", false);
}
}
In the end all I want to do is have it so when DeleteFilter is called for this test, an error is thrown and then I can assert what is returned from the catch block.
EDIT: have majorly updated the post by suggestion to make it easier to understand where the issue is.
Here is a slimmed down example
Given
public interface IServiceFactory {
object GetService(string args);
}
public class MyController : Controller {
IServiceFactory serviceFactory
public MyController(IServiceFactory serviceFactory) {
this.serviceFactory = serviceFactory;
}
// method under test
public ActionResult DeleteFilter(string args) {
try {
var model = serviceFactory.GetService(args);
return View(model);
} catch(Exception ex) {
return JsonActionResult(JsonReturnType.Error, ajaxMessage: "There was an error in deleting the filter.");
}
}
}
You can use moq in your test like this
[TestMethod]
public void DeleteFilter_ExceptionThrown_IsCaughtAndLoggedAndReturnsActionResultOfError() {
// Arrange
var serviceFactoryMock = new Mock<IServiceFactory>();
serviceFactoryMock
.Setup(x => x.GetService(It.IsAny<string>())
.Throws(new Exception())
.Verifiable();
var controller = new MyController(serviceFactoryMock.Object);
// Act
var result = controller.DeleteFilter("blah blah");
//Assert
serviceFactoryMock.Verify(); // verifies that the setup was invoked
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result, typeof(JsonActionResult));
//...other assertions
}
So now in the example when DeleteFilter is called, the mock service factory is invoked, an error is thrown based on the setup and you can assert what is returned from the catch block.

Why is moq claiming my mock's property setter is never being called even though the code is calling it?

I have the following unit test:
[TestClass]
public class DirectoryWatcherTests
{
private AutoMoqer _mocker;
private DirectoryWatcher _instance;
[TestInitialize]
public void Setup()
{
_mocker = new AutoMoqer();
_instance = _mocker.Create<DirectoryWatcher>();
}
[TestMethod]
public void Watcher_Gets_Path_Set_Same_As_Begin_Path_Parameter()
{
const string path = #"C:\test";
_instance.Begin(path);
_mocker.GetMock<FileSystemWatcherBase>()
.VerifySet(x => x.Path = path);
}
}
The code i wrote to get this to pass was:
public class DirectoryWatcher
{
private readonly FileSystemWatcherBase _fileSystemWatcher;
public DirectoryWatcher(FileSystemWatcherBase fileSystemWatcher)
{
_fileSystemWatcher = fileSystemWatcher;
}
public void Begin(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException("FileSystemWatcher passed in without a valid path already set");
_fileSystemWatcher.Path = path;
}
}
However, the VerifySet fails with:
Expected invocation on the mock at least once, but was never performed: x => x.Path = "C:\test"
Why is it claiming the setter is never being called? If it helps at all FileSystemWatcherBase is an abstract class.
Thanks to Eugene I have figured out that this seems to be an issue with Automoq and its compatibility with the latest version of Unity. I created the following tests to prove that it's an Automoq issue and not a Moq issue:
[TestMethod]
public void Test()
{
const string path = #"C:\test";
var watcherMock = new Mock<FileSystemWatcherBase>();
watcherMock.Object.Path = path;
watcherMock.VerifySet(x => x.Path = path);
}
[TestMethod]
public void Test2()
{
const string path = #"C:\test";
var mocker = new AutoMoqer();
var instance = mocker.Create<Tester>();
var watcherMock = mocker.GetMock<AbstractTest>();
watcherMock.Object.Path = path;
watcherMock.VerifySet(x => x.Path = path);
}
[TestMethod]
public void Test3()
{
const string path = #"C:\test";
var mocker = new AutoMoqer();
var instance = mocker.Create<Tester>();
var watcherMock = mocker.GetMock<AbstractTest>();
instance.Run(path);
watcherMock.VerifySet(x => x.Path = path);
}
[TestMethod]
public void Test4()
{
const string path = #"C:\test";
var testMock = _mocker.GetMock<AbstractTest>();
var tester = new Tester(testMock.Object);
tester.Run(path);
testMock.VerifySet(x => x.Path = path);
}
public abstract class AbstractTest
{
public abstract string Path { get; set; }
}
public class Tester
{
private readonly AbstractTest _test;
public Tester(AbstractTest test)
{
_test = test;
}
public void Run(string path)
{
_test.Path = path;
}
}
Tests 1, 2 and 4 pass while 3 fails. I was able to find a work around the issue via the following test case:
[TestMethod]
public void Test5()
{
const string path = #"C:\test";
var mocker = new AutoMoqer();
var watcherMock = mocker.GetMock<AbstractTest>();
var instance = mocker.Create<Tester>();
instance.Run(path);
watcherMock.VerifySet(x => x.Path = path);
}
Essentially having Automoq get me the mock prior to creating the class I'm trying to test allows the verify to work. This leads me to believe that Automoq does not realize a moq was already created for the tested class and thus a call to GetMock<T> creates a new one.

Categories

Resources