Sorry, this is likely a very amateur question, but I am struggling to understand how to use Moq properly. I am quite new to unit testing as a whole, but I think I'm starting to get the hang of it.
So here's my question... I have this snippet of code below which is using a TestServer in Visual Studio that I using for am Unit Testing... I'm trying to mock IGamesByPublisher so that my test is not reliant on data in the repository (or would it be better to mock GamesByPublisher?... Or do I need to do both?)
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<IGamesByPublisher, GamesByPublisher();
}).AddAuthorization("fake.account", null);
[Fact] // 200 - Response, Happy Path
public async Task GamesByPublisher_GamesByPublisherLookup_ValidRequestData_Produces200()
{
// Arrange
var server = ServerWithRepositoryService;
// Act
var response = await server.GetAsync(Uri);
// Assert
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
Here is the IGamesByPublisher
public interface IGamesByPublisher interface.
{
Task<IEnumerable<Publisher>> Execute(GamesByPublisherQueryOptions options);
}
}
I tried
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<Mock<IGamesByPublisher>, Mock<GamesByPublisher>>();
}).AddAuthorization("fake.account", null);
And then I tried
// Not exactly what I attempted, but that code is long gone...
var mock = new Mock<IGamesByPublisher >();
var foo = new GamesByPublisherQueryOptions();
mock.Setup(x => x.Execute(foo)).Returns(true);
I didn't really find great documentation on using Moq, just the quick start guide on GitHub, which I wasn't sure how to apply (probably my own level of experience at fault there...).
I am obviously missing some fundamentals on using Moq...
You were close.
public static TestServerWithRepositoryService => new TestServer(services => {
var mock = new Mock<IGamesByPublisher>();
var publishers = new List<Publisher>() {
//...populate as needed
};
mock
.Setup(_ => _.Execute(It.IsAny<GamesByPublisherQueryOptions>()))
.ReturnsAsync(() => publishers);
services.RemoveAll<IGamesByPublisher>();
services.AddScoped<IGamesByPublisher>(sp => mock.Object);
}).AddAuthorization("fake.account", null);
The above creates the mock, sets up its expected behavior to return a list of publishers any time Execute is invoked with a GamesByPublisherQueryOptions.
It then removes any registrations of the desired interface to avoid conflicts and then registers the service to return the mock any time the interface is requested to be resolved.
Related
I'm trying to write unit test for TranslateResponse().
private async Task TranslateResponse(Policy policy)
{
foreach(t in translatorFactory.BuildTranslator())
{
var policyTranslator=t as IPolicyAwareTranslator;
policyTranslator?.SetPolicy(policy);
}
}
The TranslateResponse() has many other translators though, but for now, I limited it to just one.
The BuildTranslator is as
public async Task<List<ITranslator>> BuildTranslators()
{
return new List<ITranslator>()
{
new PolicyTranslator()
}
}
Here I'm returning the PolicyTranslator which implements ITranslator and IPolicyAwareTranslator
ITranslator has Translate() while IPolicyAwareTranslator has SetPolicy(Policy policy) respectively.
Now that for Unit testing, I create a Mock of ITranslator and set it up and I create the Mock of IPolicyTranslator via As<>.
Mock<ITranslator> mockedTranslator=new Mock<ITranslator>();
mockedTranslator.Setup(t => t.Translate(_translatorDataAccessor.Object));
var mockedPolicyTranslator = mockedTranslator.As<IPolicyAwareTranslator>();
mockedPolicyTranslator.Setup(t => t.SetPolicy(It.IsAny<Policy>()));
List<ITranslator> translators = new List<ITranslator>(new List<ITranslator>() { mockedTranslator.Object });
translatorFactory.Setup(t => t.BuildTranslators(It.IsAny<string>())).ReturnsAsync(translators);
Still the verify call fails.
I'm I going in the right direction or missing something?
mockedPolicyTranslator.Verify(t => t.SetPolicy(new UnknownPolicy()), Times.AtLeastOnce);
The argument matcher will need to be loosened
mockedPolicyTranslator.Verify(t => t.SetPolicy(It.IsAny<UnknownPolicy>()), Times.AtLeastOnce);
since currently used new UnknownPolicy() instance wont match whatever is passed while testing
I have a simple hub that I am trying to write a test for with FakeItEasy and the verification of calling the client is not passing. I have the example working in a separate project that uses MOQ and XUnit.
public interface IScheduleHubClientContract
{
void UpdateToCheckedIn(string id);
}
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
var all = A.Fake<IScheduleHubClientContract>();
var id= "123456789";
hub.Clients = clients;
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
A.CallTo(() => clients.All).Returns(all);
hub.UpdateToCheckedIn(id);
}
I'm using Fixie as the Unit Test Framework and it reports:
FakeItEasy.ExpectationException:
Expected to find it once or more but no calls were made to the fake object.
The sample below works in XUnit & MOQ:
public interface IScheduleClientContract
{
void UpdateToCheckedIn(string id);
}
[Fact]
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
var all = new Mock<IScheduleClientContract>();
hub.Clients = clients.Object;
all.Setup(m=>m.UpdateToCheckedIn(It.IsAny<string>())).Verifiable();
clients.Setup(m => m.All).Returns(all.Object);
hub.UpdateToCheckedIn("id");
all.VerifyAll();
}
I'm not sure what I've missed in the conversion?
You're doing some steps in a weird (it looks to me, without seeing the innards of your classes) order, and I believe that's the problem.
I think your key problem is that you're attempting to verify that all.UpdateToCheckedIn must have happened before even calling hub.UpdateToCheckedIn. (I don't know for sure that hub.UpdateToCheckedIn calls all.UpdateToCheckedIn, but it sounds reasonable.
There's another problem, where you configure clients.Setup to return all.Object, which happens after you assert the call to all.UpdateToCheckedIn. I'm not sure whether that's necessary or not, but thought I'd mention it.
The usual ordering is
arrange the fakes (and whatever else you need)
act, but exercising the system under test (hub)
assert that expected actions were taken on the fakes (or whatever other conditions you deem necessary for success)
I would have expected to see something more like
// Arrange the fakes
var all = A.Fake<IScheduleHubClientContract>();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
A.CallTo(() => clients.All).Returns(all); // if All has a getter, this could be clients.All = all
// … and arrange the system under test
var hub = new ScheduleHub();
hub.Clients = clients;
// Act, by exercising the system under test
var id = "123456789";
hub.UpdateToCheckedIn(id);
// Assert - verify that the expected calls were made to the Fakes
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
There seems to be little information about how to write good unit tests for actual ASP.NET Core controller actions. Any guidance about how to make this work for real?
I've got a system that seems to be working pretty well right now, so I thought I'd share it and see if it doesn't help someone else out. There's a really useful article in the Entity Framework documentation that points the way. But here's how I incorporated it into an actual working application.
1. Create an ASP.NET Core Web App in your solution
There are tons of great articles out there to help you get started. The documentation for basic setup and scaffolding is very helpful. For this purpose, you'll want to create a web app with Individual User Accounts so that your ApplicationDbContext is setup to work with EntityFramework automatically.
1a. Scaffold a controller
Use the information included in the documentation to create a simple controller with basic CRUD actions.
2. Create a separate class library for your unit tests
In your solution, create a new .NET Core Library and reference your newly created web app. In my example, the model I'm using is called Company, and it uses the CompaniesController.
2a. Add the necessary packages to your test library
For this project, I use xUnit as my test runner, Moq for mocking objects, and FluentAssertions to make more meaningful assertions. Add those three libraries to your project using NuGet Package Manager and/or Console. You may need to search for them with the Show Prerelease checkbox selected.
You will also need a couple of packages to use EntityFramework's new Sqlite-InMemory database option. This is the secret sauce. Below are a list of the package names on NuGet:
Microsoft.Data.Sqlite
Microsoft.EntityFrameworkCore.InMemory [emphasis added]
Microsoft.EntityFrameworkCore.Sqlite [emphasis added]
3. Setup Your Test Fixture
Per the article I mentioned earlier, there is a simple, beautiful way to set up Sqlite to work as an in-memory, relational database which you can run your tests against.
You'll want to write your unit test methods so that each method has a new, clean copy of the database. The article above shows you how to do that on a one-off basis. Here's how I set up my fixture to be as DRY as possible.
3a. Synchronous Controller Actions
I've written the following method that allows me to write tests using the Arrange/Act/Assert model, with each stage acting as a parameter in my test. Below is the code for the method and the relevant class properties in the TestFixture that it references, and finally an example of what it looks like to call the code.
public class TestFixture {
public SqliteConnection ConnectionFactory() => new SqliteConnection("DataSource=:memory:");
public DbContextOptions<ApplicationDbContext> DbOptionsFactory(SqliteConnection connection) =>
new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlite(connection)
.Options;
public Company CompanyFactory() => new Company {Name = Guid.NewGuid().ToString()};
public void RunWithDatabase(
Action<ApplicationDbContext> arrange,
Func<ApplicationDbContext, IActionResult> act,
Action<IActionResult> assert)
{
var connection = ConnectionFactory();
connection.Open();
try
{
var options = DbOptionsFactory(connection);
using (var context = new ApplicationDbContext(options))
{
context.Database.EnsureCreated();
// Arrange
arrange?.Invoke(context);
}
using (var context = new ApplicationDbContext(options))
{
// Act (and pass result into assert)
var result = act.Invoke(context);
// Assert
assert.Invoke(result);
}
}
finally
{
connection.Close();
}
}
...
}
Here's what it looks like to call the code to test the Create method on the CompaniesController (I use parameter names to help me keep my expressions straight, but you don't strictly need them):
[Fact]
public void Get_ReturnsAViewResult()
{
_fixture.RunWithDatabase(
arrange: null,
act: context => new CompaniesController(context, _logger).Create(),
assert: result => result.Should().BeOfType<ViewResult>()
);
}
My CompaniesController class requires a logger, that I mock up with Moq and store as a variable in my TestFixture.
3b. Asynchronous Controller Actions
Of course, many of the built-in ASP.NET Core actions are asynchronous. To use this structure with those, I've written the method below:
public class TestFixture {
...
public async Task RunWithDatabaseAsync(
Func<ApplicationDbContext, Task> arrange,
Func<ApplicationDbContext, Task<IActionResult>> act,
Action<IActionResult> assert)
{
var connection = ConnectionFactory();
await connection.OpenAsync();
try
{
var options = DbOptionsFactory(connection);
using (var context = new ApplicationDbContext(options))
{
await context.Database.EnsureCreatedAsync();
if (arrange != null) await arrange.Invoke(context);
}
using (var context = new ApplicationDbContext(options))
{
var result = await act.Invoke(context);
assert.Invoke(result);
}
}
finally
{
connection.Close();
}
}
}
It's almost exactly the same, just setup with async methods and awaiters. Below, an example of calling these methods:
[Fact]
public async Task Post_WhenViewModelDoesNotMatchId_ReturnsNotFound()
{
await _fixture.RunWithDatabaseAsync(
arrange: async context =>
{
context.Company.Add(CompanyFactory());
await context.SaveChangesAsync();
},
act: async context => await new CompaniesController(context, _logger).Edit(1, CompanyFactory()),
assert: result => result.Should().BeOfType<NotFoundResult>()
);
}
3c. Async Actions with Data
Of course, sometimes you'll have to pass data back-and-forth between the stages of testing. Here's a method I wrote that allows you to do that:
public class TestFixture {
...
public async Task RunWithDatabaseAsync(
Func<ApplicationDbContext, Task<dynamic>> arrange,
Func<ApplicationDbContext, dynamic, Task<IActionResult>> act,
Action<IActionResult, dynamic> assert)
{
var connection = ConnectionFactory();
await connection.OpenAsync();
try
{
object data;
var options = DbOptionsFactory(connection);
using (var context = new ApplicationDbContext(options))
{
await context.Database.EnsureCreatedAsync();
data = arrange != null
? await arrange?.Invoke(context)
: null;
}
using (var context = new ApplicationDbContext(options))
{
var result = await act.Invoke(context, data);
assert.Invoke(result, data);
}
}
finally
{
connection.Close();
}
}
}
And, of course, an example of how I use this code:
[Fact]
public async Task Post_WithInvalidModel_ReturnsModelErrors()
{
await _fixture.RunWithDatabaseAsync(
arrange: async context =>
{
var data = new
{
Key = "Name",
Message = "Name cannot be null",
Company = CompanyFactory()
};
context.Company.Add(data.Company);
await context.SaveChangesAsync();
return data;
},
act: async (context, data) =>
{
var ctrl = new CompaniesController(context, _logger);
ctrl.ModelState.AddModelError(data.Key, data.Message);
return await ctrl.Edit(1, data.Company);
},
assert: (result, data) => result.As<ViewResult>()
.ViewData.ModelState.Keys.Should().Contain((string) data.Key)
);
}
Conclusion
I really hope this helps somebody getting on their feet with C# and the awesome new stuff in ASP.NET Core. If you have any questions, criticisms, or suggestions, please let me know! I'm still new at this, too, so any constructive feedback is invaluable to me!
There is this codebase where we use automapper and have 2 layers, Domain and Service. Each has its object for data representation, DomainItem and ServiceItem. The service gets data from domain, the uses constructor injected automapper instance to map
class Service
{
public ServiceItem Get(int id)
{
var domainItem = this.domain.Get(id);
return this.mapper.Map<DomainItem, ServiceItem>(domainItem);
}
}
Assume best practices, so mapper has no side-effects and no external dependencies. You'd write a static function to convert one object to another within seconds, just mapping fields.
With this in mind, is it a good practice to mock the mapper in unit tests like this?
[TestClass]
class UnitTests
{
[TestMethod]
public void Test()
{
var expected = new ServiceItem();
var mockDomain = new Mock<IDomain>();
// ... setup
var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<DomainItem, ServiceItem>(It.IsAny<DomainItem>()))
.Returns(expected);
var service = new Service(mockDomain.Object, mockMapper.Object);
var result = service.Get(0);
Assert.AreEqual(expected, result);
}
}
To me, it seems that such unit test does not really bring any value, because it is effectively testing only the mocks, So i'd either not write it at all OR I'd use the actual mapper, not the mocked one. Am I right or do I overlook something?
I think the issue here is that the test is badly written for what it is actually trying to achieve which is testing Service.Get().
The way I would write this test is as follows:
[TestMethod]
public void Test()
{
var expected = new ServiceItem();
var mockDomain = new Mock<IDomain>();
var expectedDomainReturn = new DomainItem(0); //Illustrative purposes only
mockDomain.Setup(x => x.DomainCall(0)).Returns(expectedDomainReturn); //Illustrative purposes only
var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<DomainItem, ServiceItem>(It.IsAny<DomainItem>()))
.Returns(expected);
var service = new Service(mockDomain.Object, mockMapper.Object);
var result = service.Get(0);
mockDomain.Verify(x => x.DomainCall(0), Times.Once);
mockMapper.Verify(x => x.Map<DomainItem, ServiceItem>(expectedDomainReturn), Times.Once);
}
This test instead of not really checking the functionality of the service.Get(), checks that the parameters passed are correct for the individual dependency calls based on the responses. You are thus not testing AutoMapper itself and should not need to.
Checking result is basically useless but will get the code coverage up.
I'm following TDD and ran into a problem where if I make one test succeed, two others fail due to an exception being thrown. Well, I want to throw the exception, but I also want to verify the other behaviors. For instance:
public class MyTests {
[Fact]
public void DoSomethingIsCalledOnceWhenCheckerIsTrue()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(true);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
sut.CheckAndDo();
checker.VerifyGet(x => x.PassesCheck, Times.Once());
doer.Verify(x => x.Do(),Times.Once());
}
[Fact]
public void DoSomethingIsNeverCalledWhenCheckerIsFalse()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(false);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
sut.CheckAndDo();
doer.Verify(x => x.Do(),Times.Never());
}
[Fact]
public void ThrowCheckDidNotPassExceptionWhenCheckDoesNotPass()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(false);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
}
}
What are my choices for approaching this? What, if any, would be the "preferred" choice?
Your 1st and 2nd test passes. Then when you add the 3rd test the rest of the tests fails!.
With TDD
"Avoid altering existing tests that pass. Instead, add new tests.
Change existing tests only when the user requirements change."
I also assume your SUT (System Under Test) as below
public void CheckAndDo() {
var b = _checker.PassesCheck;
if (b) {
_doer.Do();
}
throw new CheckDidNotPassException();
}
In your SUT, when you throw a new exception, obviously it has an effect on the rest of the behaviour the way you have implemented execution logic.
So the option here would be to change the existing test(s).
Give it a well named test method, and Assert both exception and the verification.
[Test]
public void CheckAndDo_WhenPassesCheckTrue_DoCalledOnlyOnceAndThrowsCheckDidNotPassException()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(true);
var sut = new ThingThatChecksAndDoes(checker.Object, doer.Object);
Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
doer.Verify(x => x.Do(), Times.Once());
}
Few other things you need to consider:
a. TDD produces good Unit tests. Good means, readable, maintainable and trustworthy Unit Tests.
Your test method names and the calls to SUT are poorly named. I guess this is just for the demo/Stackoverflow question. But I suggest in future you provide a real world example with real names other than "Do" "Something"
Having ambiguous names does not help from the TDD point of view as you are designing your system in small based on the requirements.
b. Publish the correct code.
In your first test you passing Mock types
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
var sut = new ThingThatChecksAndDoes(checker, doer);
You should pass the instances i.e (checker.Object)
When I test similar methods
I do not write a test, that x.Do() is not called
I check that exception is thrown and x.Do() is not called in one test because these two Assertions are related to the same flow.