Best practices to generate schema for production with NHibernate - c#

I am now ready to use NHibernate to persist my data layer access. I used DDD until that point and I use fake for unit tests and for the test site.
I know that I can use SchemaExport for unit/integration tests of my NHibernate concrete repositories but how should I generate the schema to be used for the test site ?
Should I create a special class in my tests that create the schema and insert the static data or should I generate the schema at the launch of the site if the database is not created ?

Personally I like to use a small console application which loads all the mappings and executes a SchemaExport as below:
new SchemaExport(config).Execute(ddlScript => {
using (var writer = new StreamWriter(fileName, true))
{
writer.Write(ddlScript);
writer.Flush();
}
}, false, false);
This console app runs as a step of the build script and the DDL script file then gets picked up by WiX and is included in the MSI package (which generates the whole database at install time).

As a simple scenario you can miss use a unit test for that. Just create unit test called CreateSchema which will do the schemaexport. Then run it before you will run the other tests.
I have a similar question here on STO

For your full build script I'd go with Markus's suggestion, for just running your unit tests
I'd put
<property name="hbm2ddl.auto">create-drop</property>
in the app config of you test project - this will drop and recreate your schema everytime all the tests are run. Each unit test can add the data it needs to test.

Related

Is it possible to test SQL data in a C# unit test?

public ApplicationLayout Get(string objectName, string userName)
{
using (var db = new SqlConnection(_connectionString))
{
var sql = "SELECT * FROM dbo.ApplicationLayout WHERE ObjectName = #ObjectName AND UserName=#UserName";
return db.Query<ApplicationLayout>(sql, new {ObjectName = objectName, UserName = userName}).FirstOrDefault();
}
}
I have some code here, and I was wondering if it is possible to perform a unit test in C# using SQL data (any framework). From what I've seen, it is not possible. Can anyone please confirm this?
I always did my testing on a dedicated database. You can do a setup and a tear down, and basically recreate the database (or restore it from a backup) each time you run those tests. It is a lot more involved than just plain C# unit testing. Like some comments stated, it's not really unit testing anymore but stuff needs to be tested one way or another.
Possible, but not recommended for a unit test.
When you talk about a unit test, you're usually talking about a test that can be repeatably executed in isolation; that is, it has no dependencies outside the code assembly where it lives (and ideally each test should not go very far beyond a single class being tested), and has no lasting side effects regardless of how the test is started or stopped (doesn't require use of the file system, or a database, etc). This is because unit tests, being the smallest and most fine-grained tests, are intended to test the code that you yourself wrote. You didn't write SQL Server, so SQL Server shouldn't be in the scope of a unit test.
Now, once you widen the scope to integration tests and acceptance tests, now you're testing that code you wrote plays nicely with all the external dependencies you didn't write. Integration tests can touch external data, like databases, and can write to as well as read from those external stores, as long as they clean up after themselves properly, either by returning a persistent database to its original condition after the run, or just using a portable DB like SQLite or MSS Express, setting up the necessary schema and test data as part of your test setup, and then just blowing the DB away when it's done.
For many, this is splitting hairs, and unit testing frameworks like MSTest or NUnit don't prevent you using them to create a test that has external dependencies. These are merely good ideas for structuring your full test suite into a fine-grained, fast-running, repeatable component that you can run on any change you make, and the longer-running, wider-scoped proof of correctness that might run overnight.
The modern approach to orchestrate testing against a real SQL engine has to work:
locally on dev machines (that run Windows, MacOS or Linux);
build pipelines in the cloud (e.g. Azure DevOps pipelines, GitHub Actions,
etc.).
TL;DR – check out DbSample on GitHub, a sample EF Core based
project with fully automated tests against MS SQL Server and a GitHub
Actions pipeline.
A detailed analysis of orchestrating tests is covered in "Pain & Gain of automated tests against SQL (MS SQL, PostgreSQL)" article. The key steps are:
Launch SQL engine in Docker (use official images for SQL Server or PostgreSQL)
Create a test database and populate the schema, logic, lookup dictionaries, etc (via command line for the containers)
Connect xUnit/NUnit tests to the database and for each test (rinse and repeat):
Seed test data
Perform the testable activity and checks
Revert the database to the pristine state (via Respawn)
Tear down the SQL engine along with the database and other artefacts.
P.S. I know, the OP said "unit tests" but perhaps meant a more broad "automated tests"

Data driven unit test in combination with LocalDB not working in VSTS

I have a problem running data driven unit tests (MSTest) in VSTS. My situation is the following:
In my C# solution I have a MSTest-test project which contains three test classes that contain data driven test methods.
These methods used to work with an attached MDF-file as data source, but for reasons of maintainability I added a database-project to my solution which contains the scripts to create and fill a database with my test data.
The test-project also contains an initialize method (marked with the AssemblyInitialize attribute) which deploys the dacpac from the database-project) to a LocalDB-instance. For this deployment I use the Microsoft.SqlServer.DACFx NuGet-package.
The data driven test methods all use the following connection string
Data Source=(LocalDB)\v11.0;Initial Catalog=Enkoni_Validation_Tests;Integrated Security=True;Connect Timeout=30
The problem is that this solution workes locally without any problems, but when I trigger a build on VSTS, most of the tests run fine, but one test class constantly failes with the message
"The unit test adapter failed to connect to the data source or to read the data. (...) Error details: Cannot open database "Enkoni_Validation_Tests" requested by the login. The login failed."
The testmethods in the other two classes run without any problems. Since all three test classes are part of the same project, I assume the initialization (the deployment of the DacPac) runs without problems.
Has anyone experienced a similar problem or does anyone know how to solve this?
Edit (added some additional information): the build runs on a hosted build agent and it's always the same test that fails. I have considered that maybe there is some sort of limitation on how many connections can be made to the LocalDB database, but I can't find any information that supports this theory. And since all my tests run sequential, I also don't expect that there are many (or even more than one) connections.

Should unit tests in Test Explorer connect to a database?

Should unit tests in Test Explorer connect to a database?
I can execute the same code outside of the test case and it correctly inserts into the database. When trying to test the repository (that performs the insert) within a unit test written in Visual Studio test explorer, the insert does not happen.
Unit tests are supposed to test your business layer logic/methods. It should not be inserting to the database. You should be using a fake data access layer( Use a mocking library like Moq / FakeItEasy) if needed.
A quick example using Moq library.
var repoMoq = new Mock<IRepository>();
repoMoq.Setup(s=>s.GetStudentName(It.IsAny<int>)).Returns("Test Student");
var bl = new StudentManagementBusinessLayerClass(repoMoq.Object);
// To do : Assert Something now.
// Ex : bl.GetStudent(234);
Here you are mocking your Data access layer,IRepository's GetStudentMethod to return "TestStudent" when it is being called from the Unit test.
End to end Integration tests are the one you need where you execute a full cycle which inserts data to db and once your testing is done, Delete /Rollback the test data.

Integration Testing Adding a database file to my test project .How can I do it

I need to do some integration testing. At the moment I have some scripts that run once per assembly that create the db if not exists and populate it.
I thought it would be better if I could add a databaseFile to the test project and then just populate and clear the db accordingly. Even if this is not the best way
How do I add a database file eg "MyTestDB.mdf to my project. I am using VS 2010 premium Edition.
Suggestions?
I made some experiments with this a couple of years ago and arrived at the conclusion that the fastest way to integration test against SQL Server is to have the database itself (including schema) as an Immutable Shared Fixture, but without any data in.
As part of Fixture Teardown, all tables are truncated, leaving a clean database for the next test case. Each test case fill the database with the data it needs as part of building up its Fixture. A few years back I described this approach and it's still the best that I know of.
I've also experimented with attaching and detaching database files, but it turned out that the above process was faster.

How do I close or "uninitialize" Castle ActiveRecord?

I'm running some unit tests using Castle ActiveRecord that interact with a database. I have a procedure to drop the database (if it exists), then re-create it, before I interact with it in each test.
If I run one test, this works fine.
If I run multiple tests, the second one fails because it can't drop the database.
Is there some way in Castle ActiveRecord to tell it to shut down and let go of the database?
Instead of dropping the whole database, I recommend dropping and recreating the schema.
To drop the schema: ActiveRecordStarter.DropSchema();
To create the schema: ActiveRecordStarter.CreateSchema();
To reinitialize ActiveRecord: ActiveRecordStarter.ResetInitializationFlag(); then reconfigure it.
See the base AR test class for guidance.
For testing, I recommend taking a look at the new InMemoryTest.
See also: docs for ActiveRecord unit-testing.

Categories