How do I mock PolicyResult to contain a value for FinalException? - c#

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()));
}

Related

How to use DbContext.Database in C# unit test cases using MOQ and Xunit

The problem statement looks lengthy but I have tried my best to make it as simple as possible.
I have a small function inside SchedulerLPOP10ReportDataView class which uses DbContext Object as:
public async Task<IEnumerable<T>> GetReportViewData<T>(OneFpsReportsDbContext dbContext)
{
var defaultTimeOut = dbContext.Database.GetCommandTimeout();
dbContext.Database.SetCommandTimeout(new TimeSpan(0,20,0));
var results = await dbContext.VW_Report.FromSqlRaw($"SELECT * from [Analytics].[VW_LPOP10_Report_Scheduling]).ToListAsync();
dbContext.Database.SetCommandTimeout(defaultTimeOut);
return (IEnumerable<T>)(results);
}
The OneFpsReportsDbContext class syntax looks like:
public partial class OneFpsReportsDbContext : DbContext
{
public OneFpsReportsDbContext()
{
}
public OneFpsReportsDbContext(DbContextOptions<OneFpsReportsDbContext> options)
: base(options)
{
}
//code
}
I have written test case as:
[Fact]
public void GetReportViewData_OK()
{
// Arrange
var unitUnderTest = new SchedulerLPOP10ReportDataView(It.IsAny<int>());
var mockSet = new Mock<DbSet<DbContext>>();
var MockOneFpsReportsDbContext1 = new Mock<OneFpsReportsDbContext>();
TimeSpan ts3 = TimeSpan.FromMinutes(20);
MockOneFpsReportsDbContext1.Setup(x => x.Database.SetCommandTimeout(ts3)); //[1] error
//Act
var res = unitUnderTest.GetReportViewData<ISchedularReportDataView>(MockOneFpsReportsDbContext1.Object, WhereClause, sqlParameters).Result;
//Assert
}
At [1] error I get this:
Unsupported expression: ... => ....SetCommandTimeout(ts3) Extension
methods (here: RelationalDatabaseFacadeExtensions.SetCommandTimeout)
may not be used in setup / verification expressions.
I also tried the 'UseInMemoryDatabase' approach but I came to know we can't use 'GetCommandTimeout' with it.
What Am I missing or doing incorrect in the //Arrange section of my test case? And How exactly can I make this mock / work?
Thanks.
This is, unfortunately, one of the hard-to-overcome limitations of XUnit/in-memory DB combo. You basically have two choices:
Spin up an actual test database locally for your unit testing purposes. In this case you'll be closer to production, but your test would kinda turn from unit into integration since you'll lack proper isolation
Create a wrapper class around the DbContext plus extension methods you need and mock that class instead.
The latter will look like this:
public class DbContextWrapper: OneFpsReportsDbContext
{
public void SetCommandTimeout(TimeSpan ts)
{
this.Database.SetCommandTimeout(ts);
}
}
// Then inside the usage block
public async Task<IEnumerable<T>> GetReportViewData<T>(DbContextWrapper dbContext)
{
var defaultTimeOut = dbContext.Database.GetCommandTimeout();
dbContext.SetCommandTimeout(new TimeSpan(0,20,0));
var results = await dbContext.VW_Report.FromSqlRaw($"SELECT * from [Analytics].[VW_LPOP10_Report_Scheduling]").ToListAsync();
dbContext.Database.SetCommandTimeout(defaultTimeOut);
return (IEnumerable<T>)(results);
}
// And in the test:
[Fact]
public void GetReportViewData_OK()
{
// Arrange
var unitUnderTest = new SchedulerLPOP10ReportDataView(It.IsAny<int>());
var mockSet = new Mock<DbSet<DbContext>>();
var MockOneFpsReportsDbContext1 = new Mock<DbContextWrapper>();
TimeSpan ts3 = TimeSpan.FromMinutes(20);
MockOneFpsReportsDbContext1.Setup(x => x.SetCommandTimeout(ts3)); //[1] error
//Act
var res = unitUnderTest.GetReportViewData<ISchedularReportDataView>(MockOneFpsReportsDbContext1.Object, WhereClause, sqlParameters).Result;
//Assert
}

Possible repo pattern question or how to create one mock instance form multiple mock instances?

I'd like to test my logic which expects three different interfaces. How can I unite these, because I can't use mock methods while I have three instances. I guess I did something very wrong with the repositories but I have no idea. Thank you for your help!
[Test]
public void TestThatLogicABCWorks()
{
Mock<IRepositoryA> mockInstance1 = new Mock<IRepositoryA>();
Mock<IRepositoryB> mockInstance2 = new Mock<IRepositoryB>();
Mock<IRepositoryC> mockInstance3 = new Mock<IRepositoryC>();
LogicABC logic = new LogicABC(mockInstance1.Object, mockInstance2.Object, mockInstance3.Object);
}
Edit: i have three entity classes, 1 general repository and three entity specific repos. In logic I make queries including all three entities, which I reach as:
public class LogicABC : ILogic
{
IRepository<A> ARepo; //generic repo
IRepository<B> BRepo;
IRepository<C> CRepo;
public LogicABC(IARepository ARepo, IBRepository BRepo, ICRepository CRepo)
{
this.ARepo = ARepo; //entity specific repos
this.BRepo = BRepo;
this.CRepo = CRepo;
}
public LogicABC()
{
var Entity = new ABCEntities(); //context
this.ARepo = new ARepository(Entity);
this.BRepo = new BRepository(Entity);
this.CRepo = new CRepository(Entity);
}
//queries
public List<int> Query1()
{
var q1 = from x in CRepo.GetAll()
select x.Id;
return q1.ToList();
}
I need to test these queries with mock. For example setup that logicABC.Query1() returns 1 and then verify it.
When testing a subject under test that has dependencies, the dependencies explicitly needed for the test to flow to complete should be provided.
In this case Query1() is only using ICRepository and has not shown any interaction with the other two dependencies. If that is truly the case then those other dependencies are not needed.
Based on the method under test the following assumptions are being made
public interface ICRepository : IRepository<C> {
//...
}
and something similar for the other repositories IARepository and IBRepository.
public interface IRemository<TEntity> {
IEnumerable<TEntity> GetAll();
//...other members
}
public class C {
public int Id { get; set; }
//...other members
}
So the test for Query1 could be done as follows.
[Test]
public void LogicABC_Query1_Should_Return_One_Id() {
//Arrange
int expected = 123456789;
var items = new [] { new C { Id = expectedId } }
Mock<IRepositoryC> mock = new Mock<IRepositoryC>();
mock.Setup(_ => _.GetAll()).Returns(items);
LogicABC logic = new LogicABC(null, null, mock.Object);
//Act
List<int> list = logic.Query1();
//Assert
mock.Verify(_ => _.GetAll(), Times.Once());
//checking expected behavior - using FluentAssertions
list.Should().HaveCount(1);
int actual = list.First();
actual.Should().Be(expected); // using FluentAssertions
}
The unit test above tests the expected behavior of one subject method. The same pattern can be done for other members of the class under test.
You need to mock methods in every repository mock, i.e. in mockInstance1, mockInstance2 and mockInstance3. After this you'll be able to verify behavior inside LogicABC by checking applied mocks for every repos
UPDATE:
Your test should look like this:
[Test]
public void TestThatLogicABCWorks()
{
Mock<IRepositoryA> mockInstance1 = new Mock<IRepositoryA>();
mockInstance1.Setup(foo => foo.Do()).Returns(() => 1);
Mock<IRepositoryB> mockInstance2 = new Mock<IRepositoryB>();
mockInstance2.Setup(boo => boo.Do2()).Returns(() => 2);
Mock<IRepositoryC> mockInstance3 = new Mock<IRepositoryC>();
mockInstance3.Setup(doo => doo.Do3()).Returns(() => 3);
LogicABC logic = new LogicABC(mockInstance1.Object, mockInstance2.Object, mockInstance3.Object);
logic.DoLogic();
// do some asserts here
}

How to return DbRawSqlQuery in Moq setup method

I have a procedure service which contain only methods like this one:
DbRawSqlQuery<UserVesselPermissionsResult> GetUserVesselPermissions(Guid userId, DateTime date);
So, all the methods are returning DbRawSqlQuery, then in some upper layer of the application I turn them into IEnumerable. But for the testing purpose in some places I have to setup this method. The problem is that the class DbRawSqlQuery does have a internal constructor(I know Moq does not accept internal constructors) but I dont know if there is some way to make this code work:
_procedureService.Setup(x => x.GetUserVesselPermissions(It.IsAny<Guid>(), It.IsAny<DateTime>()))
.Returns(new DbRawSqlQuery<UserVesselPermissionsResult>(null));
Currently it does not work due to DbRawSqlQuery which can not be instantiated easily.
EDIT 1:
Here are some more details:
public class IMembershipService
{
private readonly IProcedureService _procedureService;
public MembershipService(IProcedureService procedureService)
{
_procedureService = procedureService;
}
public List<UserVesselPermissionsResult> UserPermissions => _procedureService.GetUserVesselPermissions(UserId, DateTime.Now).ToList();
public bool UserHasPermissionOrAdmin(YcoEnum.UIPermission permission)
{
if (IsUserAdministrator)
return true;
var userVesselPermissions = UserVesselPermissions; //Here I have to make the setup
if (userVesselPermissions == null)
return false;
var userSelectedVesselId = UserSelectedVesselId;
return //something
}
}
The test method would look like this:
[TestCase(true)]
[TestCase(false)]
public void UserHasAllPermissionsOrAdmin_IsAdminOrNot_ReturnsTrue(bool isAdmin)
{
//Arrange
_membershipService.IsUserAdministrator = isAdmin;
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, "rajmondi#outlook.com"),
new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString())
};
var identity = new ClaimsIdentity(claims, "TestAuthType");
var claimsPrincipal = new ClaimsPrincipal(identity);
_authenticationManager.Setup(x => x.User).Returns(claimsPrincipal);
_procedureService.Setup(x => x.GetUserVesselPermissions(It.IsAny<Guid>(), It.IsAny<DateTime>()))
.Returns((DbRawSqlQuery<UserVesselPermissionsResult>) null);//Here I dont know how to set it up due to DbRawSqlQuery
//Action
var result = _membershipService.UserHasAllPermissions(It.IsAny<YcoEnum.UIPermission>());
//Assert
Assert.That(result, Is.EqualTo(true));
}
Any help is much appreciated!
Cheers!
I could make it work, I actually did not like the idea of changing the whole IProcedureService just because it does return a built-int type from entity framework. Since I get the data from the procedure service and return them to IEnumerable I only had to care for GetEnumerator() method, so what I thought would be to check first how the code was constructed inside, I found that DbSqlQuery was inheriting from DbRawSqlQuery and did not have the problem of internal constructor. In this case I created a new class called TestDbSqlQuery which would inherit from the DbSqlQuery. The class look like this:
public class TestDbSqlQuery<T> : DbSqlQuery<T> where T : class
{
private readonly List<T> _innerList;
public TestDbSqlQuery(List<T> innerList)
{
_innerList = innerList;
}
public override IEnumerator<T> GetEnumerator()
{
return _innerList.GetEnumerator();
}
}
I added purposely the Lis<T> as a param so I can store my data in that list and then use my overriden IEnumerator<T>.
So, now the test method would be like this:
_procedureService.Setup(x => x.GetUserVesselPermissions(It.IsAny<Guid>(), It.IsAny<DateTime>()))
.Returns(new TestDbSqlQuery<UserVesselPermissionsResult>(new List<UserVesselPermissionsResult>
{
new UserVesselPermissionsResult
{
PermissionId = 1
}
}));
and it is working fine, at the end the TestDbSqlQuery can be modified as needed but the idea is the same, just store the objects in some container and then retrieve them in GetEnumerator method.

Moq Method called by System.Threading.Tasks.Task.Factory.StartNew

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.

Mocked Object Still Making Calls to Service

So I'm writing tests for our MVC4 application and I'm testing Controller actions specifically. As I mention in the title, the test still hits the service (WCF) instead of returning test data. I have this controller:
public class FormController : Controller
{
public SurveyServiceClient Service { get; set; }
public SurveyDao Dao { get; set; }
public FormController(SurveyServiceClient service = null, SurveyDao dao = null)
{
this.Service = service ?? new SurveyServiceClient();
this.Dao = dao ?? new SurveyDao(Service);
}
//
// GET: /Form/
public ActionResult Index()
{
var formsList = new List<FormDataTransformContainer>();
Dao.GetForms().ForEach(form => formsList.Add(form.ToContainer()));
var model = new IndexViewModel(){forms = formsList};
return View("Index", model);
}
And it uses this DAO object:
public class SurveyDao
{
private readonly SurveyServiceClient _service;
private readonly string _authKey;
public SurveyDao(SurveyServiceClient serviceClient)
{
_service = serviceClient;
}
....
public FormContract[] GetForms()
{
var forms = _service.RetrieveAllForms();
return forms;
}
And this is my test using JustMock, the mock on GetForms() returns some test data in a helper class:
[TestClass]
public class FormControllerTest
{
private SurveyDao mockDao;
private SurveyServiceClient mockClient;
public FormControllerTest()
{
mockClient = Mock.Create<SurveyServiceClient>();
mockDao = Mock.Create<SurveyDao>(mockClient);
}
[TestMethod]
public void TestIndexAction()
{
//Arrange
var controller = new FormController(mockClient, mockDao);
Mock.Arrange(() => mockDao.GetForms()).Returns(TestHelpers.FormContractArrayHelper);
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.IsInstanceOfType(result.Model, typeof(IndexViewModel));
}
}
My problem is that when I run the test, the Service is still being called. I've verified this using Fiddler as well as debugging the test and inspecting the value of "result" which is populated with our service's test data.
EDIT:
I've changed the test constructor to be a [TestInitialize] function, so the Test now looks like this:
[TestClass]
public class FormControllerTest
{
private SurveyDao mockDao;
private SurveyServiceClient mockClient;
[TestInitialize]
public void Initialize()
{
mockClient = Mock.Create<SurveyServiceClient>();
mockDao = Mock.Create<SurveyDao>(Behavior.Strict);
}
[TestMethod]
public void TestIndexAction()
{
//Arrange
var controller = new FormController(mockClient, mockDao);
Mock.Arrange(() => mockDao.GetForms()).Returns(TestHelpers.FormContractArrayHelper);
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.IsInstanceOfType(result.Model, typeof(IndexViewModel));
}
}
Please verify that you are using the correct assembly for JustMock. There are a few different ones (VisualBasic, Silverlight, JustMock). The JustMock one is the one you should be including in your project.
Failure to include the correct one will cause the behavior that you are describing (method not being properly stubbed).
The JustMock manual explains (highlights by me):
By default Telerik JustMock uses loose mocks and allows you to call
any method on a given type. No matter whether the method call is
arranged or not you are able to call it.
You can control this behavior when calling the Create() method of you Mock:
var foo = Mock.Create<IFoo>(Behavior.Strict);
There you can specify what the mock object should do if you have not explicitly implemented a certain method. In your case (I think it is the default behavior) the mock indeed calls the original method on the object that you want to mock.
You have the following choices in the Behavior Enumeration enumeration:
Loose: Specifies that by default mock calls will behave like a stub, unless explicitly setup.
RecursiveLoose: Specifies that by default mock calls will return mock objects, unless explicitly setup.
Strict: Specifies that any calls made on the mock will throw an exception if not explictly set.
CallOriginal: Specifies that by default all calls made on mock will invoke its corresponding original member unless some expecations are set.

Categories