Test method still calls the actual method despite mock - c#

So I have some initial setup that looks like this:
ILoginManager _loginManager;
Mock<IValidations> _validations;
Mock<IAccountRepository> _accountRepository;
[SetUp]
public void Setup()
{
_loginManager = new LoginManager();
_validations = new Mock<IValidations>();
_accountRepository = new Mock<IAccountRepository>();
}
Then I have the test method that looks like this:
[Test]
public void Login_ValidUser()
{
_validations.Setup(val => val.IsValidAccount(It.IsAny<User>())).Returns(true);
_accountRepository.Setup(repo => repo.Login(It.IsAny<User>())).Returns(()=>new User());
var result = _loginManager.Login(new User());
Assert.That(result, Is.Not.Null);
}
And the actual method that looks like this:
public User Login(User user)
{
if (user != null && _validations.IsValidAccount(user))
{
return _accountDal.Login(user);
}
log.Error("User null or not valid");
return null;
}
The problem is that the test method still calls the original methods so it ignores the mock setup.

Those dependencies would have had to have been injected directly into the manager in order for them to be available for mocking when testing
For example
public class LoginManager : ILoginManager {
private readonly IValidations _validations;
private readonly IAccountRepository _accountDal;
public LoginManager(IValidations validations, IAccountRepository accountDal) {
_validations = validations;
_accountDal = accountDal;
}
public User Login(User user) {
if (user != null && _validations.IsValidAccount(user)) {
return _accountDal.Login(user);
}
log.Error("User null or not valid");
return null;
}
}
Your current example is not using the mocks in the class under test because they were not injected.
Refactor the LoginManager class and the test accordingly
ILoginManager _loginManager;
Mock<IValidations> _validations;
Mock<IAccountRepository> _accountRepository;
[SetUp]
public void Setup() {
_validations = new Mock<IValidations>();
_accountRepository = new Mock<IAccountRepository>();
_loginManager = new LoginManager(_validations.Object, _accountRepository.Object);
}
[Test]
public void Login_ValidUser() {
//Arrange
var expected = new User();
_validations.Setup(val => val.IsValidAccount(It.IsAny<User>())).Returns(true);
_accountRepository.Setup(repo => repo.Login(It.IsAny<User>())).Returns(()=> user);
//Act
var actual = _loginManager.Login(expected);
//Assert
Assert.That(actual, Is.Not.Null);
Assert.AreEqual(expected, actual);
}

Related

Mock an Async Task method returns null using C# and Xamarin

I've read and test all these answers (this, this and this) but didn't help (also it's not my first use of mocking in such a situation, but this case is rare for me).
I'm using moq and xunit for my unit testing purpose. In testing ViewModel I mocked service and page and passed them to it, everything is working but not page.CountDialog that returns null, this is my code:
Page.cs:
public interface IPage
{
Task<PromptResult> CountDialog(decimal previousCount);
}
PageViewModel:
public class PageViewModel : ViewModelBase<ObservableRangeCollection<Detail>>
{
private readonly IPage _page;
private readonly IService _service;
private ICommand _editItemCommand;
public PageViewModel(IService service, IPage page)
{
_service = service;
_page = page;
Data = new ObservableRangeCollection<Detail>();
}
public ICommand EditItemCommand
{
get => _editItemCommand ??
(_editItemCommand = new Command<Detail>(async (o) => { await EditItem(o); }));
set => _editItemCommand = value;
}
public async Task EditItem(Detail detail)
{
if (detail == null) return;
try
{
var result = await _page.CountDialog(detail.Count); // It should return PromptResult (from UserDialogs lib) but every time is null, in normal running app, it works and is Not null
if (result == null) return; //in test is usually null
if (!result.Ok || string.IsNullOrWhiteSpace(result.Text)) return;
var newCount = Convert.ToInt32(result.Text);
var res = await _service.EditItem(detail, newCount);
if (res.Status)
UpdatePageItem(detail, newCount);
}
catch (RestException exception)
{
// nothing
}
}
}
ViewModelTest.cs:
public class ViewModelTest
{
Mock<IService> _service = new Mock<IService>();
Mock<IPage> _page = new Mock<IPage>();
private PageViewModel _viewModel;
public PageViewModelTest()
{
_viewModel = new PageViewModel(_service.Object, _page.Object);
}
[Fact]
public async Task EditItemTest_SuccessAsync()
{
var pageItems = GetItemsFake();
var result = new PromptResult(true, "12"); // the result i wish to be returned (but is usually null)
_page.Setup(x => x.CountDialog(It.IsAny<int>())).ReturnsAsync(result); // this is mock part that not work
_service.Setup(x => x.GetItems(It.IsAny<int>())).ReturnsAsync(pageItems);// works
_service.Setup(c => c.EditItem(It.IsAny<int>(), It.IsAny<Detail>(), It.IsAny<int>())).ReturnsAsync(
new ActionResponse
{
Result = "OK"
});//works
_viewModel.LoadDataCommand.Execute(true);
await _viewModel.EditItem(pageItems .ElementAt(0)); // after this line code goes to _viewModel class and there is null
// _viewModel.EditItemCommand.Execute(pageItems.ElementAt(0)); // Also checked this one too, but not work too
Assert.Equal(12, _viewModel.Data.ElementAt(0).Count); // not passed due to not working mock
}
}
That's because CountDialog takes a decimal not an int.
Try this:
_page.Setup(x => x.CountDialog(It.IsAny<decimal>())).ReturnsAsync(result);

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.

verifying setup on a passed in mocked object

I am testing my class
public class myclass
{
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject)
{
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest()
{
this.awesomeObject.RunSomething(); //I want to verify that RunSomething was called
}
}
The way I am doing this is:
//Arrange
var mockAwesome = new Mock<IAwesome>();
mockAwesome.Setup(x=>x.RunSomething()).Returns ... Verify()...;
//Act
var sut = new myclass(mockAwesome.object);
sut.MethodUnderTest();
//Assert
mockAwesome.Verify();
The exception I am getting is:
System.NotSupportedException : Expression references a method that
does not belong to the mocked object: x => x.RunSomething
Is it not possible to test that a specific method was executed on a mocked object that I passed into a class, that is now part of a private member of that class?
Modify set up line to mockAwesome.Setup(x=>x.RunSomething()).Verifiable() and it should work for the example you provided.
[TestClass]
public class MoqVerificationTest {
[TestMethod]
public void Moq_Should_Verify_Setup() {
//Arrange
var mockAwesome = new Mock<IAwesome>();
mockAwesome.Setup(x => x.RunSomething()).Verifiable();
//Act
var sut = new myclass(mockAwesome.Object);
sut.MethodUnderTest();
//Assert
mockAwesome.Verify();
}
public interface IAwesome {
void RunSomething();
}
public class myclass {
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject) {
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest() {
this.awesomeObject.RunSomething(); //I want to verify that RunSomething was called
}
}
}
To confirm, comment out this.awesomeObject.RunSomething() in your sample class and run the test again. It will fail because you setup the RunSomething as Verifiable() and it was not used.
When testing, works perfectly fine for me...
Try this approach see if anything different results...
void Main()
{
IAwesome awesome = Mock.Of<IAwesome>();
Mock<IAwesome> mock = Mock.Get(awesome);
mock.Setup(m => m.RunSomething());
MyClass myClass = new MyClass(awesome);
myClass.MethodUnderTest();
mock.Verify(m => m.RunSomething(), Times.Once);
}
public interface IAwesome
{
void RunSomething();
}
public class MyClass
{
private IAwesome awesomeObject;
public myclass(IAwesome awesomeObject)
{
this.awesomeObject = awesomeObject;
}
public void MethodUnderTest()
{
this.awesomeObject.RunSomething();
}
}

How to return null when accessing a moq object?

I am using Moq library for unit testing. Now what i want is that when I access my object for the first time it should return null, and when i access this on second time it should return something else.
here is my code
var mock = new Mock<IMyClass>();
mock.Setup(?????);
mock.Setup(?????);
var actual = target.Method(mock.object);
in my method i am first checking that whether mock object is null or not, if it is null then do initialize it and then do some calls on it.
bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
else
{
myObj = new MyClass();
bool result = myObj.SomeFunctionReturningBool();
return result;
}
}
what to do setup for mock object,
Also i need to know how to mock this line
bool result = myObj.SomeFunctionReturningBool();
It sounds like you are trying to run two tests with one test method - maybe it would be better to split the tests into two?
You also want to initialise a new object if the method is passed null. To test this, I suggest creating a factory object responsible for creating instances of MyClass. The new code would look like:
interface IMyClassFactory
{
IMyClass CreateMyClass();
}
bool Method(IMyClass myObj, IMyClassFactory myClassFactory)
{
if (myObj != null)
{
return true;
}
myObj = myClassFactory.CreateMyClass();
return myObj.SomeFunctionReturningBool();
}
Then the tests would look like:
[Test]
public void Method_ShouldReturnTrueIfNotPassedNull()
{
Assert.That(target.Method(new MyClass()), Is.True);
}
[Test]
public void Method_ShouldCreateObjectAndReturnResultOfSomeFunctionIfPassedNull()
{
// Arrange
bool expectedResult = false;
var mockMyClass = new Mock<IMyClass>();
mockMyClass.Setup(x => x.SomeFunctionReturningBool()).Returns(expectedResult);
var mockMyFactory = new Mock<IMyClassFactory>();
mockMyFactory.Setup(x => x.CreateMyClass()).Returns(mockMyClass.Object);
// Act
var result = target.Method(null, mockMyFactory.Object);
// Assert
mockMyClass.Verify(x => x.SomeFunctionReturningBool(), Times.Once());
mockMyFactory.Verify(x => x.CreateMyClass(), Times.Once());
Assert.That(result, Is.EqualTo(expectedResult));
}
Here the factory pattern has been used to pass in an object which can create objects of IMyClass type, and then the factory itself has been mocked.
If you do not want to change your method's signature, then create the factory in the class's constructor, and make it accessible via a public property of the class. It can then be overwritten in the test by the mock factory. This is called dependency injection.
Moq - Return null - This working example simply illustrates how to return null using Moq. While the line of code is required is the commented line below, a full working example is provided below.
// _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
public interface IShopService
{
Product GetProduct(string productId);
}
public class ShopService : IShopService
{
public Product GetProduct(string productId)
{
if (string.IsNullOrWhiteSpace(productId))
{
return new Product();
}
return new Product { Id = "8160807887984", Name = "How to return null in Moq" };
}
}
public class Shop
{
private static IShopService _shopService;
public Shop(IShopService shopService)
{
_shopService = shopService;
}
public Product GetProduct(string productId)
{
Product product = _shopService.GetProduct(productId);
return product;
}
}
[TestClass]
public class ShopTests
{
Mock<IShopService> _mockShopService;
[TestInitialize]
public void Setup()
{
_mockShopService = new Mock<IShopService>();
}
[TestMethod]
public void ShopService_GetProduct_Returns_null()
{
//Arrange
Shop shop = new Shop(_mockShopService.Object);
//This is how we return null --- all other code above is to bring this line of code home
_mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
//Act
var actual = shop.GetProduct(It.IsAny<string>());
//Assert
Assert.IsNull(actual);
}
}
To mock a result value you can do simply:
mock.Setup(foo => foo.SomeFunctionReturningBool()).Returns(true); // or false :)
for the other question, just pass null in the unit test instead of passing mock.object and your unit test cover that too. So you basically create two unit test one with:
var actual = target.Method(mock.object);
and the other one with:
var actual = target.Method(null);
Currently your SUT is tight-coupled with MyClass implementation. You can't mock objects which are instantiated with new keyword inside your SUT. Thus you cannot test your SUT in isolation, and your test is not unit test anymore. When implementation of MyClass.SomeFunctionReturningBool will change (it will return true instead of false), tests of your SUT will fail. This shouldn't happen. Thus, delegate creation to some dependency (factory) and inject that dependency to your SUT:
[Test]
public void ShouldReturnTrueWhenMyClassIsNotNull()
{
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
Mock<IMyClass> myClass = new Mock<IMyClass>();
var foo = new Foo(factory.Object);
Assert.True(foo.Method(myClass.Object));
}
[Test]
public void ShouldCreateNewMyClassAndReturnSomeFunctionValue()
{
bool expected = true;
Mock<IMyClass> myClass = new Mock<IMyClass>();
myClass.Setup(mc => mc.SomeFunctionReturningBool()).Returns(expected);
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
factory.Setup(f => f.CreateMyClass()).Returns(myClass.Object);
var foo = new Foo(factory.Object);
Assert.That(foo.Method(null), Is.EqualTo(expected));
factory.VerifyAll();
myClass.VerifyAll();
}
BTW assignment new value to method parameter does not affect reference which you passed to method.
Implementation:
public class Foo
{
private IMyClassFactory _factory;
public Foo(IMyClassFactory factory)
{
_factory = factory;
}
public bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
return _factory.CreateMyClass().SomeFunctionReturningBool();
}
}
You can use TestFixture with parameter. this test will run two times and different type value.
using NUnit.Framework;
namespace Project.Tests
{
[TestFixture(1)]
[TestFixture(2)]
public class MyTest
{
private int _intType;
public MyTest(int type)
{
_intType = type;
}
[SetUp]
public void Setup()
{
if (_intType==1)
{
//Mock Return false
}
else
{
//Mock Return Value
}
}
}
}

Mock class method inside controller with MOQ

Using the sample code below how could I use MOQ to mock a (referenced dll) class method
[TestMethod]
public void SampleTestMethod()
{
var _controller = new MyController();
var stub = new Mock<class1>();
stub.Setup(x => x.DoSomething(It.IsAny<int>())).Returns(2);
//var retval = stub.Object.DoSomething();
var result = _controller.MyAction() as ViewResult;
stub.Verify(x => x.DoSomething(It.IsAny<int>()), Times.AtLeastOnce(), "Didn't call DoSomething");
}//end test
//Controller
public class MyController{
public MyController(){}
public virtual ActionResult MyAction(){
var ret = new class1();
var result = ret.DoSomething(10);
//rest of code
return View();
}
}
//external class
public class class1
{
public virtual int DoSomething(int i)
{
return 1;
}
}
You will need to inject an instance of the external class 'class1' into your controller's constructor. Then you can use Moq to mock it and inject in the fake one. Something like this:
public class MyController{
private readonly IClass1 _class1;
public MyController(IClass1 class1){
_class1 = class1;
}
// Other code uses this private instance
}
[TestMethod]
public void Test(){
var class1 = new Mock<Class1>();
var controller = new MyController(class1.Object);
}

Categories

Resources