There is a way to get the result returned from a method called into a mocked object?
For example, if I have the following classes and an interface:
DoSomethingClass.cs
public class DoSomethingClass
{
IInternalClass _intClass;
public DoSomethingClass(IInternalClass intClass)
{
_intClass = intClass;
}
void DoSomething(int number)
{
// do some transformation to the number, e.g.
var transformedNumber = number * (number - 1);
var x = _intClass.IsEven(transformedNumber);
// do something else
}
}
InternalClass.cs
public interface IInternalClass
{
bool IsEven(int number);
}
public class InternalClass: IInternalClass
{
public InternalClass();
public bool IsEven(int number)
{
return number % 2 == 0;
}
}
And a test class:
Tests.cs
public class Tests
{
[Fact]
public async Task test_something()
{
//PREPARE
var request = 10
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
// ACT
await classToTest.DoSomething(request);
//ASSERT
//Here I want to check if the method IsEven of the internal class return the right result
}
}
}
What I want to assert is the return value of the method IsEven of the InternalClass called inside the main method DoSomething, there is no way that I can know the transformedNumber calculated inside this method and passed to IsEven.
NOTE: I use the Moq library to mock object.
Excuse me for the stupid example above, but I don't have any simple real code to show here, however I hope this can be sufficient to understand the question.
I am assuming that you want to verify that your IsEven method is called on the mocked IInternalClass?
If that is the case then you can use the Verify method on the mock as follows:
[Fact]
public void DoSomething_Verify()
{
var request = 10;
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
classToTest.DoSomething(request);
//Verify that the mock is invoked with the expected value, the expected number of times
internalMock.Verify(v => v.IsEven(90), Times.Once);
//There are lots of other options for Times, e.g. it is never called with an unexpected value maybe.
internalMock.Verify(v => v.IsEven(91), Times.Never);
}
Also to call the DoSomething method with await you would need to change the method signature as follows:
public async Task DoSomethingAsync(int number)
{
// do some transformation to the number, e.g.
var transformedNumber = number * (number - 1);
var x = _intClass.IsEven(transformedNumber);
// do something else
}
Then you can create a unit test like this:
[Fact]
public async void DoSomething_VerifyAsync()
{
var request = 10;
var internalMock = new Mock<IInternalClass>();
var classToTest = new DoSomethingClass(internalMock.Object);
//To call the DoSomething method with await the method needs the async Task and a good convention is to append Async to the name
await classToTest.DoSomethingAsync(request);
//Another slightly more generic option is to verify that the mock was called with and int exactly n Times
internalMock.Verify(v => v.IsEven(It.IsAny<int>()), Times.Exactly(1));
}
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'm fairly new to this TDD and I'm lost with this at the moment.
I'm trying to use .Setup to get the product by ID of 99 and check it's actually returned in .Returns(saveProduct), which causes me the error below:
enter image description here
What am I doing wrong?
public class ProductControllerTests
{
private Mock<ICart> cartMock;
private Mock<IProductRepository> productRepositoryMock;
private Mock<IOrderRepository> orderRepositoryMock;
private Mock<IProductService> productServiceMock;
private Mock<ILanguageService> languageServiceMock;
private Mock<IStringLocalizer<ProductService>> stringLocalizerMock;
private ProductViewModel product;
private ProductController productController;
public ProductControllerTests()
{
//setup
product = new ProductViewModel();
cartMock = new Mock<ICart>();
productRepositoryMock = new Mock<IProductRepository>();
orderRepositoryMock = new Mock<IOrderRepository>();
stringLocalizerMock = new Mock<IStringLocalizer<ProductService>>();
productServiceMock = new Mock<IProductService>();
languageServiceMock = new Mock<ILanguageService>();
productController = new ProductController(productServiceMock.Object, languageServiceMock.Object);
}
[Fact]
public void CreateValidModelState() // MOCKED
{
// Act
ProductService productService = new ProductService(cartMock.Object, productRepositoryMock.Object, orderRepositoryMock.Object, stringLocalizerMock.Object);
productController = new ProductController(productService, languageServiceMock.Object);
productServiceMock.Setup(x => x.SaveProduct(product)); //It works without this?!? what's it FOR!?
//Arranje
product.Id = 99;
product.Name = "Test box";
product.Description = "The best box ever.";
product.Details = "Toss it and see if it gets back.";
product.Stock = "9000";
product.Price = "9000";
var saveProduct = productController.Create(product);
//productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
//productServiceMock.SetupGet(x => x.GetProductById(99)).Returns("Test box");
//var expectedProduct = productServiceMock.GetProduct(1);
Assert.IsType<RedirectToActionResult>(saveProduct);
}
}
}
There is a lot of room for improvement in your code snippet.
First, you create private members but then you over write the variable name with local variables.
The idea behind mocking is that when you mock an interface you can Setup its' methods to return whatever you wish them to return. So in your case
productServiceMock.Setup(x => x.GetProductById(99)).Returns(saveProduct);
the line above means that wherever in your controller you have the GetProductById(int) method is called with 99 as a parameter, the method will return the saveProduct object.
You could also write the Setup like
productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
In this case wherever in your controller the GetProductById() method is called, no matter what is the parameter passed, you will get the saveProductObject.
In this test you have written I can not see any value. What I mean is that create a controller, you create the saveProduct and then you assert it is not null. Of course it is not null, because you populated above.
It would make sense to actually use one of your controllers methods that you know that the GetByUserId() method is used. Then make an assertion upon the return object based on the methods logic.
---Update---
Imagine you have a handler
public class HandlerExample {
private IInjectedService _injectedService;
public HandlerExample(IInjectedService injectedService){
_injectedService = injectedService;
}
public int Handle(testNumber)
{
var serviceResponse = _injectedService.TestMethod(testNumber);
if(serviceResponse)
return 1;
return 2;
}
}
And your interface looks like
public interface IInjectedService
{
bool TestMethod(int testNumber);
}
I won't give any example on the implementation here because it is not relevant. Your test method would then make sense to be like
[Fact]
public void Test()
{
mockedInjectedService = new Mock<IInjectedService>();
mockedInjectedService.Setup(x => x.TestMethod(99)).Returns(true);
var handler = new Handler(mockedInjectedService.Object);
var sut = handler.Handle(99);
Assert.Equal(sut, 1);
}
sut is a convention for "system under test"
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);
}
}
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));
I have a testing class
public class TerminationRequestValidation : ValidatorBase<TerminationRequest>
{
public TerminationRequestValidation(IIntHR2BLLContext context) : base(context)
{
}
public override ValidationResult ValidateWithoutThrow(TerminationRequest request)
{
var result = ValidationResult.Success;
/* some logic */
var isHRIAdvanced = Context.Logics.Accessible.HasAccess(request, IntHRSecurityOperationCode.TerminationRequestSetTerminationDateBehindhand);
if (!isHRIAdvanced && Context.Logics.Termination.IsTerminationDateChanged(request))
{
result += CheckTerminationDate(request);
}
return result;
}
public virtual ValidationResult CheckTerminationDate(TerminationRequest request)
{
var result = ValidationResult.Success;
/* any validation logic */
return result;
}
}
I need to check 'CheckTerminationDate' method is performed
[TestMethod]
public void Validate_TerminationDateChangedbyNotAdvanced_TerminationDateCheck()
{
var context = FakeContext.Create();
// first stub
var accessibleBllStub = new Mock<IAccessibleBLL>(MockBehavior.Loose);
accessibleBllStub.Setup(z => z.HasAccess(It.IsAny<TerminationRequest>(), It.IsAny<IntHRSecurityOperationCode>()))
.Returns<TerminationRequest, IntHRSecurityOperationCode>((x, y) => y != IntHRSecurityOperationCode.TerminationRequestSetTerminationDateBehindhand);
context.StubBLL(z => z.Accessible, accessibleBllStub.Object);
// second stub
var terminationBLLStub = new Mock<ITerminationBLL>(MockBehavior.Loose);
terminationBLLStub.Setup(z => z.IsTerminationDateChanged(It.IsAny<TerminationRequest>())).Returns(true);
context.StubBLL(z => z.Termination, terminationBLLStub.Object);
// mock
var validator = new Mock<TerminationRequestValidation>(MockBehavior.Loose, context.MainContext);
// act
validator.Object.ValidateWithoutThrow(termination);
//assert
validator.Verify(z => z.CheckTerminationDate(It.IsAny<TerminationRequest>()));
}
This unit test off course isn't work. On the one hand I need to call real 'ValidateWithoutThrow' method, on the another hand I need to check that stub method 'CheckTerminationDate' is performed.
Guys, help me to find the best solution! May be I need to redesign testing class to make in more testable
I need to check 'CheckTerminationDate' method is performed
You don't. You need to test that the request was validated. Whether that's done inline, or by calling CheckTerminationDate, or by calling some other method, that's an implementation detail - and unit tests don't care about that.
So, your tests should look something like this:
public void ValidateWithoutThrow_ReturnsSucessfulResult_When_RequestIsValid()
{
var validRequest = //...
var validator = new TerminationRequestValidation(/*...*/); // don't mock this class
var result = validator.TerminationRequestValidation(validRequest);
Assert.Equal(ValidationResult.Success, result);
}
public void ValidateWithoutThrow_ReturnsUnsucessfulResult_When_RequestIsInvalid()
{
var invalidRequest = //...
var validator = new TerminationRequestValidation(/*...*/); // don't mock this class
var result = validator.TerminationRequestValidation(invalidRequest);
Assert.NotEqual(ValidationResult.Success, result);
}
As a general rule of thumb, avoid verifying how the method works internally. You're coupling your tests to implementation details and refactoring/maintaining those details will be a living hell.