I am using NUnit for test units. I have my interface on the domain so i am ready to make implementation of those interfaces in the persistence layer. My question is how do you actually make the unit tests for testing those repositories ? i believe this isnt a good idea to test directly from the database. Ive heard poeple that are using SQLite but it is okay to use mocks instead ? why are the poeple using SQLite for in-memory database when you can provide a mock with actuals entities ?
Any example would be welcome too.
Note: This is intended to be repositories coded in C# that gonna use NHibernate and Fluent NHibernate as mapping.
Thanks.
It of course depends, but in most cases I'd say it's generally enough to just mock the repositories in your tests and using the in-memory SQLite database only to test your mappings (FluentNHibernate Persistence specification testing).
For the NUnit mappings tests with SQLite I'm using the following base class:
public abstract class MappingsTestBase
{
[SetUp]
public void Setup()
{
_session = SessionFactory.OpenSession();
BuildSchema(_session);
}
[TestFixtureTearDown]
public void Terminate()
{
_session.Close();
_session.Dispose();
_session = null;
_sessionFactory = null;
_configuration = null;
}
#region NHibernate InMemory SQLite Session
internal static ISession _session;
private static ISessionFactory _sessionFactory;
private static Configuration _configuration;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
FluentConfiguration configuration = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory().ShowSql)
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<NHibernateSession>())
.ExposeConfiguration(c => _configuration = c);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
private static void BuildSchema(ISession session)
{
SchemaExport export = new SchemaExport(_configuration);
export.Execute(true, true, false, session.Connection, null);
}
#endregion
}
An example mappings test class deriving from the above base class could then look like the following:
[TestFixture]
public class MappingsTest : MappingsTestBase
{
[Test]
public void Persistence_Employee_ShouldMapCorrectly()
{
Category employee = new PersistenceSpecification<Employee>(_session)
.CheckProperty(e => e.Id, 1)
.CheckProperty(e => e.FirstName, "John")
.CheckProperty(e => e.LastName, "Doe")
.VerifyTheMappings();
...
Assert.Equals(employee.FirstName, "John");
...
}
}
Personally I'd do functional testing of the repositories against an actual database (possibly SQL Express). You could run those tests in CI only once a day.
All the unit tests for other classes can safely assume that the repositories work and use mock repositories.
EDIT: The above presumes that your repositories are solely used for data access; they basically just use LINQ or HQL. Keep the business logic out of them!
Related
UserController:
class UserController(private val graphRepository: GraphRepository) : Controller {
override fun installRoutes(router: Router) {
router.install {
post("/api/v1/user").handler(this#UserController::addUser)
}
}
}
Testing route and calling route handler "addUser":
#Test
fun newUserAdded() {
Mockito.`when`(mockRoutingContext.queryParam("id")).thenReturn(listOf("1"))
Mockito.`when`(mockGraphRepository.getUser("1")).thenReturn(Promise.ofSuccess(null))
Mockito.`when`(mockGraphRepository.enrollUser(any())).thenReturn(Promise.ofSuccess(Unit))
Mockito.`when`(mockRoutingContext.response()).thenReturn(mockHttpServerResponse)
Mockito.doNothing().`when`(mockHttpServerResponse).end()
UserController(mockGraphRepository).addUser(mockRoutingContext)
Mockito.verify(mockRoutingContext, Mockito.times(1)).response()
Mockito.verify(mockHttpServerResponse).end()
}
The main question is how to test the controller route without explicitly calling "addUser" on "UserController" because I want to make the controller function private.
Mocking behavior for types you don't own is generally discouraged for a variety of reasons, such as (but not limited to):
If the real implementation of the mocked dependency changes, the mock's behavior will not automatically reveal any forward-breaking changes.
The more mocks a test introduces, the more cognitive load the test carries, and some tests require a lot of mocks in order to work.
The approach that works best for me is to think of these more as integration tests, and avoid the mocks all together.
To achieve this, I've got an abstract VertxPlatform class that I extend that contains references to resources I commonly refer to across a variety of tests:
the Vertx instance itself
a Router
an EventBus
an HttpServer
a WebClient
These resources is reinitialized per invocation of each test, and the Router is subsequently associated with the HttpServer.
A typical test ends up looking something like this:
class MyHandlerIT : VertxPlatform() {
private lateinit var myHandler: MyHandler // <-- the component under test
#Before override fun setUp(context: TestContext) {
super.setUp(context) // <-- reinitializes all the underlying Vert.x components
myHandler = MyHandler()
router.post("/my/handler/path")
.handler(myHandler.validationHandler())
.handler(myHandler.requestHandler(vertx))
.failureHandler(myHandler.failureHandler())
}
#After override fun tearDown(context: TestContext) {
super.tearDown(context)
}
#Test fun status_400_on_some_condition(context: TestContext) {
val async = context.async()
testRequest(POST, path = "/my/handler/path", params = null, body = null, headers = null)
.subscribeBy(
onSuccess = { response ->
context.assertEquals(BAD_REQUEST.code(), response.statusCode())
async.complete()
},
onError = { error ->
context.fail(error)
}
)
}
}
In each individual test you might have some more case-specific setup. For example, if MyHandler gets results from your GraphRepository via the EventBus you could setup a fake Consumer within the scope of that test that replies with a pre-canned result that server back the values you were otherwise trying to mock.
Hope this helps, or at least inspires some thought!
I have a controller with two parameters and need to test them via unit tests. Want to test 4 parameters, ViewBug, etc. But how I can make fake DB context and logger? I'm stuck at this moment:
[Fact]
public void IndexReturnsAViewResultWithAListOfUsers()
{
// Arrange
var mock = new Mock<AircraftsController>();
var controller = new AircraftsController(/*params*/);
// Act
// Assert
}
This is my controller:
public class AircraftsController : Controller
{
#region DbContext, Logger
public AppDbContext Context { get; }
private readonly ILogger<AircraftsController> _logger;
public AircraftsController(AppDbContext context, ILogger<AircraftsController> logger)
{
Context = context;
_logger = logger;
_logger.LogDebug(1, "NLog injected into Controller");
}
#endregion
[HttpGet]
public IActionResult Compare(int vehicle1, int vehicle2, int vehicle3, int vehicle4)
{
var planesFromDb = Context.Planes.OrderBy(x => x.BR).ToList();
planesFromDb.Insert(0, new Plane { Image = "~/images/EmptyPlane.png", Nation = "EmptyFlag", Name = "Select aircraft", VehicleId=0 });
var selectedPlanes = new List<Plane>();
ViewBag.AllPlanesSelected = planesFromDb;
selectedPlanes.Add(planesFromDb.FirstOrDefault(p => p.VehicleId == vehicle1));
selectedPlanes.Add(planesFromDb.FirstOrDefault(p => p.VehicleId == vehicle2));
selectedPlanes.Add(planesFromDb.FirstOrDefault(p => p.VehicleId == vehicle3));
selectedPlanes.Add(planesFromDb.FirstOrDefault(p => p.VehicleId == vehicle4));
_logger.LogInformation("Log Message");
return View(selectedPlanes);
}
}
As Stephen has suggested the in-memory provider is a good option for mocking an EFCore db context. It works for most things.
I have a requirement to use Moq for 3rd party dependencies so I'd create mocks for both. For the db context I'd use EntityFrameworkCore.Testing (disclaimer, I am the author):
var mockedDbContext = Create.MockedDbContextFor<AppDbContext>();
Then for the logger I'd create a mock using Mock.Of
var mockedLogger = Mock.Of<ILogger<AircraftsController>>();
Easy one liners that you can then use to create your controller in your unit test. Overall I am an advocate of using the EFCore in-memory provider if it suits the unit test. Using mocks does have other advantages such as allowing you to verify invocations.
In .NET Core, you can take advantage of in-memory databases for unit tests. There are two options, EF In-Memory database, and SQLite In-Memory database. I prefer SQLite In-Memory because it gives you all the advantages of handling relational data, unlike EF In-Memory.
Testing with the EF In-Memory Database
SQLite In-Memory Database
Below is a simple implementation for unit tests using SQLite In-Memory database:
public YourContext GetDbContext()
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var option = new DbContextOptionsBuilder<YourContext>()
.UseSqlite(connection,
s => {
s.UseNetTopologySuite();
s.MigrationsHistoryTable("__MigrationHistory");
}).Options;
var dbContext = new YourContext(option);
//Added to recreate database and run migration for each test.
if (dbContext != null)
{
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
}
return dbContext;
}
And then in unit test:
var context = GetDbContext();
Alternatively, you can place the GetDbContext method in a fixture, so that you are only re-creating the database one time per test class. Have a dispose method in the fixture to run the dbContext.Database.EnsureDeleted() to clean up the data between test classes.
Shared context between Tests - Class Fixtures
I am using Rhino.Mocks and Structure map to help unit test my code. I have several tests that pass when they are ran by themselves, but when ran as a group fail to pass. The setup code for these unit tests is:
[TestInitialize()]
public void Setup()
{
ObjectFactory.Initialize(x =>
{
x.For(IManager)().Use(Handler)();
});
}
In my tests, I stub out this interface and call the method.
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return(null);
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsFalse(areMultiple);
}
Test Method 2
[TestMethod]
public void AreMultiple_Test()
{
var mackIManager = MockRepository.GenerateMock<IManager>();
mackIManager.Stub(u => u.GetTwoUserName(Arg<int>.Is.Anything)).Return("123");
ObjectFactory.Inject(typeof(IManager), mackIManager);
StepAdditionalActionBase actionBase = new StepAdditionalActionBase();
bool areMultiple = actionBase.AreMultiple(new WorkOrder { Id = "123" });
Assert.IsTrue(areMultiple);
}
This is unit testing the following code.
public bool AreMultiple(WorkOrder workOrder)
{
string secondUser = _handler.GetTwoUserName(_workflowManager.GetNumberForProject(workOrder.Id));
if (String.IsNullOrEmpty(secondUser ))
{
return false;
}
return true;
}
When I run them by themselves, they work fine. When I run them together, the first passes and the second fails. When I debug the second one, I find that that the return value in the Stubbed method is still coming back as null. How do I get this to use the new Stubbed method.
UPDATE.
I am using StructureMap as my container. From what I have been able to find, the following code is what is used to dispose of the container I got it from this link. When I added this, the test still fail when ran together, but pass when ran individually.
[TestCleanup()]
public void TestCLeanup()
{
ObjectFactory.Container.Dispose();
}
The tests work one by one but fails if run all together. The problem should be in the common part which is being shared across the tests making them dependent from each other. In this particular case that is static ObjectFactory which is nothing else but a Service Locator (anti-pattern).
In the tests, you mock the IManager interface and register it in the ObjectFactory:
ObjectFactory.Inject(typeof(IManager), mackIManager);
Then the SUT uses the ObjectFactory service locator to resolve and use the mocked interface (_handler field):
string secondUser = _handler.GetTwoUserName(...)
I suspect the first test registers the _handler and never clean it up properly, so that the same instance appears in the second test. You should reset the ObjectFactory between tests following the Register Resolve Release pattern.
Another (preferable) option is to refactor your SUT to receive the IManager handler dependency explicitly via constructor. That would simplify both SUT and tests moving the ObjectFactory configuration to the Composition Root.
I'm working on unit tests for a grails application. I've been successful at testing services and domains but stuck trying to test classes in the src/groovy folder. What do I have to do to access the saveCreateAndCall method?
#Artefact("Controller")
#Transactional(readOnly = true)
class BaseController<T> extends RestfulController<T> {
protected def saveCreateAndCall(Object instance, boolean flush = false, Closure c) {
if (instance.save(flush: flush)) {
c.call instance
} else {
errorCreateResponse(instance)
}
}
any advice or feedback would be appreciated, thanks
You can create your BaseController as an abstract class and let it in the controllers folder.
abstract class BaseController<T> {
}
Normally I tend to create an concrete controller to test my base abstraction and use the #TestFor to use the Grails testing features for controllers.
Or you can annotate your test:
#GrailsUnitTestMixin
#Mock(MyDomainClass)
class BaseControllerTest extends Specification {
}
When unit testing with NHibernate I will typically have tests that create and save an object, clear the session (session.Clear()) then retrieve the object from the database.
What's the equivalent of Session.Clear() with EF4?
Example test:
[Test]
public void Can_create_and_save_a_default_account()
{
var account = new Account();
_db.Accounts.AddObject(account);
_db.SaveChanges();
int id = account.AccountId;
// clear session
var fromDb = _db.Accounts.SingleOrDefault(x => x.AccountId == id);
Assert.IsNotNull(fromDb);
}
That will be recreating your DataContext-derived class (_db in your case).
You could mock your remote database with in-memory database. Here is example
SO after each test you will start from scratch.