I am having an issue while testing one of the service method which uses an async Repository method.
Repository layer
public interface IRepo
{
Task<Model> GetByIdAsync(string Id);
Task SaveAsync(Model model);
}
Service layer
void Process(string Id)
{
var model = _repo.GetByIdAsync(Id).Result;
model.Field1 = "update";
_repo.SaveAsync(model).Wait();
}
Unit test against service layer
[Fact]
SUTServiceTest()
{
//Arrange
Model model = new Model();
var mockRepo = Mock.Get(new Repo());
mockRepo.Setup(x => x.GetByIdAsync(It.IsNotNull<string>()))
.Returns(() => Task.FromResult(model));
mockRepo.Setup(x => x.SaveAsync(It.IsAny<Model>()))
.Callback<Model>((obj) => model = obj);
var _service = new SUTService(mockRepo);
//Act
_service.Process("1");
//Assert
Assert.Equal("update", model.Field1);
}
I'm getting the following error at _repo.SaveAsync(model).await();:
System.NullReferenceException - Object reference not set to an instance of an object
Not sure what did I miss.
The intent behind this answer is to capture valuable information from the chat discussion.
As the OP said a NullReferenceException has been thrown at the following line:
_repo.SaveAsync(model).Wait();
The _repo tried to be initialized in the following way in the unit test:
var mockRepo = Mock.Get(new Repo());
That's not the correct way to do it. Please check the documentation of the Mock.Get to know when it should be used and for what purpose.
The _repo should be initialized in the following way:
var mockRepo = new Mock<IRepo>();
The OP had the following observation after changing the mock creation:
However, I loose the DI setup that I have for Repo construction
In short: That's the whole point.
Whenever you are unit testing a component then you try to mock out (simplify and mimic) all of its dependencies. It needs to rely on stubs and spies to be able to verify which one of them have been called under certain circumstances but the concrete implementation of the mocked objects do not matter.
In this particular case that means that the Service layer do not want to rely on a concrete Repository instance. It needs only a repo, which can capture the calling parameters and which can verify its calling.
FYI: Testing terminologies
Dummy: simple code that returns bogus data
Fake: a working alternative which can take shortcuts
Stub: custom logic with predefined data
Mock: custom logic with expectations (interactive stub)
Shim: custom logic at run-time
Spy: interceptors to record calls
Related
I am using flurl and I am trying to unit test the code below:
public class MyRestClient
{
public async Task<T> Request<T>(IFlurlRequest flurlRequest)
{
try
{
return await flurlRequest
.WithOAuthBearerToken("my-hardcoded-token")
.GetAsync()
.ReceiveJson<T>();
}
catch(HttpFlurlException)
{
throw new MyCustomException();
}
}
}
What I want to test is that if flurlRequest throws an exception of type HttpFlurlException then it will throw MyCustomException. My idea is to moq the flurlrequest and throw an exception. This is how I layed out my test:
var moq = Substitute.For<IFlurlRequest>();
// Problem is with line below:
moq.When(x => x.WithOAuthBearerToken("dummy")).Do(x => { throw new HttpFlurlException(); } );
var myClient = new MyRestClient();
Func<Task> call = async () => { await myClient.Request<object>(moq); };
// FluentAssertions
call.Should().Throw<MyCustomException>();
The code when ran returns a NullReferenceException:
Exception has occurred: CLR/System.NullReferenceException
An exception of type 'System.NullReferenceException' occurred in
Flurl.Http.dll but was not handled in user code: 'Object reference not
set to an instance of an object.'
at Flurl.Http.HeaderExtensions.WithHeader[T](T clientOrRequest, String name, Object value)
So I see its something related to headers... so I tried also mocking that by adding:
var moq = Substitute.For<IFlurlRequest>();
moq.Headers.Returns(new Dictionary<string, object> { {"dummy", new {} };
But I'm constantly getting the same exception. What am I doing wrong?
WithOAuthBearerToken is an extension method, which means it cannot be mocked directly by NSubstitute. When you call When..Do or Returns on an extension method it will run the real code of the extension method. (I recommend adding NSubstitute.Analyzers to your test project to detect these cases.)
Tracing through the extension method implementation at the time of writing, it should be possible to mock the Headers property to throw the required exception, but I think this is dragging in much too much internal knowledge of the library and will result in brittle tests that are tightly coupled to that specific implementation (which is what we are aiming to avoid with mocking!).
I would be very wary of mocking out a third part library in this way, as I outlined in this answer:
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of [a third-party library], rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
If possible I suggest trying to use Flurl's built-in testing support instead. That should enable you to fake out the behaviour you need without requiring specific details about Flurl's internal implementation.
I am attempting to setup a simple unit test for my code. I have an interface and implementation that talks to an external service via WCF. I am attempting to mock this with the code below;
private Mock<IPayments> _mockIPayments;
_mockIPayments.Setup(x => x.GetCreditCard(It.IsAny<GetCreditCardRequest>())).Returns(getCreditCardResponse);
In the unit test itself, I create an instance of the service that would ultimately call the WCF service;
var paymentService = new PaymentService();
var response = paymentService.GetCardDetails(cardId);
Within the PaymentService itself, the code;
var response = ServiceInvoker.Invoke<IPayments, GetCreditCardRequest, GetCreditCardResponse>
(
"Payments",
request,
(proxy, req) => proxy.GetCreditCard(req));
(Note that ServiceInvoker.Invoke is just a wrapper to create a channel and process the request)
Am I missing something, should the mock setup not be catching the request to GetCreditCard?
ETA
To make it a little clearer, the flow is;
UnitTest -> PaymentsService -> IPayments
You need to pass your mocked instance to the service somehow.
var paymentService = new PaymentService(_mockIPayments.Object);
Simply specifying a setup will not let Moq replace all instances of some interface with the what you specified. It simply defines what Moq will return when a certain Mock instance will be called. In your case _mockIPayments.
You then have to use that mocked IPayments instance in your code (either pass it in a constructor or method) for your code to actually use it.
If your PaymentService is currently creating an IPayments object internally, to use mocking you will have to use something like Dependency Injection so that you are able to specify the IPayments instance externally and thus supply a mock instance in your tests.
Likewise:
var paymentService = new PaymentService(_mockIPayments.Object);
I've got a controller with a lot of constructor injection:
public MoviesController(ISession session, IClientContext clientContext, PManager pManager, ISegmentationService segmentationService, IGeoLocator geoLocator, IBus bus)
{
_session = session;
_clientContext = clientContext;
_pManager = pManager;
_segmentationService = segmentationService;
_geoLocator = geoLocator;
_bus = bus;
}
From my understanding (just read about Mocking), I've got a lot of Mock object properties to manually set if I wish to make a comprehensive test suite based on this controller.
For one method I'm only using one service (I'd even like to automate that with little effort if possible):
public object Show(Guid id)
{
var movie = _session.Get<movie>(id);
return movie;
}
But in another there are many services being used - is there any way to set those Moq objects up quickly? I could really use some examples as I'm new to testing. It's an asp.net mvc project with webapi 1 bundled in (testing the webapi controller here)
As has been said in the comments, if you have common setup code, you can put it in a Setup method that is called automatically from your testing framework before each test. It's decorated with a Setup attribute if you're using Nunit TestInitialize if you're using MStest. If you're using XUnit then it's a bit different.
So, your class might look like this:
public class SomeTests {
Mock<ISession> _sessionMock;
Mock<IClientContext> _clientContextMock;
[Setup]
public void Setup() {
_sessionMock = new Mock<ISession>();
_clientContextMock = new Mock <IClientContext();
}
MovieController CreateSut() {
return new MovieController(_sessionMock.Object, _clientContextMock.Object, ...);
}
[Test]
public void TestSomething() {
_sessionMock.Setup(x=>...);
//...
var sut = CreateSut();
//...
}
}
If you're trying to get away from completely creating the mocks manually, then you might want to look at something like AutoFixture with AutoMoq. Which will automatically supply mock instances when creating objects that accept interfaces. AutoFixture can be quite useful, but there is a learning curve to using it effectively so you might want to look at a tutorial / quickstart.
You could also configure an IOC container to supply mock instances for your test project, although I've never gone down that route myself.
For your example, you only need to mock the session, and can leave all the other dependencies null, since their behaviour should be irrelevant to the behaviour you are testing:
Mock<ISession> mockSession = new Mock<ISesssion>();
MoviesController controller = new MoviesController(mockSession.Object, null,null,null,null,null);
There is no need for you to set up any mocks other than the ones you need for this particular test
First off, I am new to Quartz.net and Moq.
I am trying to unit test Quartz.net Execute method using Moq. The Execute() is defined in the IJob interface. The Execute method needs an IJobExecutionContext to be passed to it.
I have created a new job class named RunItinerary that inherits from the IJob interface. Below is an example of what I have.
public class RunItinerary : IJob
{
public RunItinerary()
{
}
public RunItinerary(IBFDatabase db) : base(db)
{
}
public override void Execute(IJobExecutionContext context)
{
// magic happens
}
}
Below is an example of my unit test. I have been unsuccessful in all my attempts to run a simple unit test. Here is an example of a test I tried.
var mockIJobExecutionContext = new Mock<IJobExecutionContext>();
var runItinerary = new RunItinerary();
runItinerary.Execute(mockIJobExecutionContext.Object);
mockIJobExecutionContext.VerifyAll();
Below is the error: (the x's are to mask internal names)
Test method xx.xxxxxx.xxxxxxxx.xxxJobs.UnitTest.RunItineraryTest.Execute_Success threw exception:
xx.common.Data.Exceptions.DatabaseConfigurationSectionNotFoundException: JobDatabase
at xx.common.Data.Abstract.xxDatabase..ctor(String configSectionName) in xxDatabase.cs: line 39
at xx.windows.Scheduler.Data.JobDatabase..ctor(String configSectionName) in JobDatabase.cs: line 24
at xx.windows.Scheduler.Data.JobDatabase..ctor() in JobDatabase.cs: line 20
at xx.windows.Scheduler.Jobs.BaseJob..ctor() in BaseJob.cs: line 45
at xx.windows.Scheduler.xxxJobs.RunItinerary..ctor() in RunItinerary.cs: line 31
at xx.windows.Scheduler.xxxJobs.UnitTest.RunItineraryTest.Execute_Success() in RunItineraryTest.cs:
line 177
I believe something that I am missing is in the mockIJobExecutionContext.Setup(x => x.???????), I just cannot figure out what it is that I need to do with the .Setup()
I have reviewed similar posted questions about unit testing this Execute() but there has not been a clear answer with sample code.
If someone can provide an answer can you please provide a sample unit test for this?
It seems that the RunItinerary (the class you are testing) has a 'default' behaviour when it comes to its dependency on IBFDatabase, which seems to be to new up an instance of a concrete class JobDatabase. Because this is a unit test, the JobDatabase is failing presumably because of missing configuration (e.g. connection strings etc)
xx.windows.Scheduler.Data.JobDatabase..ctor() in JobDatabase.cs: line 20
Fortunately, it would appear that you have an alternate RunItinerary constructor allowing you to provide the IBFDatabase dependency:
var mockJobExecutionContext = new Mock<IJobExecutionContext>();
var mockBFDatabase = new Mock<IBFDatabase>();
// You may need to do the minimal required Setups on `mockBFDatabase` here
var runItinerary = new RunItinerary(mockBFDatabase.Object); // i.e. use the other ctor
runItinerary.Execute(mockIJobExecutionContext.Object);
mockJobExecutionContext.Verify(x => x.SomeMethod(someParam), Times.Once);
mockBFDatabase.Verify(x => x.FetchSomeData(theIdIAmExpecting), Times.Once);
Although it is quite commonplace when retrofitting unit tests (and dependency injection) into legacy code to have 'fallbacks' which couple classes to their dependencies if no injected dependency is provided, I would recommend that you try remove these ASAP to eliminate the coupling to concrete dependencies and replace this with an IoC container managed strategy - this way you can be 100% sure that the code you are unit testing is indeed the real production code.
I'm doing an ASP.Net MVC2 project and developing some unit test cases on it. In one of my controllers,
String AllowedActions = "";
AllowedActions = entities.sp_IsAuthorized(GetLoggedUserId(), 1, item.SubCategoryId, "CreateMeeting_HTML").FirstOrDefault();
I was unable to mock this sp_IsAuthorized() method ,
public ObjectResult<global::System.String> sp_IsAuthorized(.....){
}
I tried to mock it in this way,
var entity = new Mock<TestMVCProductEntities>();
entity.Setup(x => x.sp_IsAuthorized(...)).Return(???);
but I have no clue how to return
ObjectResult
this type of object. Help me.
You can't create a new instance of ObjectResult and you can't mock it because it is marked as sealed. I would recommend you to wrap your usage of the data context into a unit of work or similar pattern, making it testable in a unit test.