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"
Related
I need to write integration tests for my layer that exposes methods of service. But I need my database to be in a certain state for the tests to pass
For example for testing the GetStoreByID method, I need to have store 1 in my database but not store 2 (for the ko test)
The database is developed and deployed by a another team using a sql project (dacpac)
I use Entity Framework 6.1.3 with an Edmx
What is the best way, in this case, to setup the data in database before tests ?
This link https://msdn.microsoft.com/en-us/library/dn314431(v=vs.113).aspx gives the Microsoft MSDN article on how to write tests using EF6 by faking out the database.
In summary the article covers the subject 'When writing tests for your application it is often desirable to avoid hitting the database. Entity Framework allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data.'
If your data access is separated by an interface (i.e. using something like IDBSet for each of the types), personally I'd avoid depending on the database completely where possible, and use either a fakedbsets (if you need to test repository/DAL code) or just mocking with moq or nsubstitute if you don't.
I know this doesn't specifically answer your question, but the best way to setup test data is do it in memory in my experience with as few external dependencies as possible. The database adds extra moving parts that you don't really want to have to depend on in unit/integration tests. This also adds complexities if you have a CI server etc... that you generally want to avoid.
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.
I have written a .Net application which has many components, some of those components are database access layers which abstract from the rest of the components where the data comes from.
I have unit tested the rest of the components by mocking the database access layer. One way I have of testing the database access layers is to use create new empty databases on the test servers. This can be slow, and most would argue that it is not a unit tests as I depend on the database server.
What I think I want, is a mocked database which I can use to test my database access layer. The mocked database can be given a schema and process SQL commands as if it were a remote database, but in fact it is all in-memory. Does this exists? Or how else can I test my SQL and database <-> data model code.
To solve my problem you may want to know I am using SQL Server, versions 2008 and later, and my code is written in C#, running with .Net 4.5 and using Visual Studio 2013
Note: I do not want to use Linq2SQL/EntityFramework to replace my database access layer, as in my experience it results difficult to debug issues and performance problems.
I tried to phrase my question carefully to avoid people lecturing me on their beliefs in what should be tested and how, but perhaps to be a little more blunt:
I want to unit test my SQL, small changes to that have a big impact on the outcome of the program. I do have integration tests, but it takes much longer to create a release for the test environment than it does to tweak code and run the unit tests.
I appreciate people taking the time to read my question and respond anyhow.
I don't know if it's going to be the best answer, but. The way we're doing is that we're using SQLite, which is an in-memory database. There are a number of different ways to set it up, we use NHibernate as an ORM, and for that it is fairly easy to set up using FluentNHibernate, but I don't think it's much harder using any other framework either:
Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => ... )
.BuildConfiguration()
.BuildSessionFactory();
I think you can run queries against a SQLite database without any ORMs as well, e.g. using the base SqlConnection class.
This database can accept migrations, schemas, etc. It behaves very close to a proper MsSql database, we can run any DDL an DML statements against it, and it works fine. Since it's all in-memory, it's also pretty fast.
I have a time consuming operation that needs tested. The operation makes changes to a database. Current, the majority of my tests are very similar, a query is performed on the database to determine the expected result after the operation. Then, the operation under test is ran. Finally, the database is again queried to determine if the expected condition has been met. Since I am only querying the database in each test to determine the expected and actual results, and the function under test is always performing the same operations on the database. Is there a way that I could run the operation once and still test each condition in its own test?
The standard strategy for running unit tests on code that has side effects such as connecting to databases is to provide mock objects instead of a real database connection or other service, but it depending on how your code is structured this may be harder or easier to adopt.
Frameworks for inversion of control and dependency injection can be very helpful for this kind of purpose. The dependancy injection pattern makes sure that objects can have dependant implementations passed to them at runtime, rather than constructing them directly, for testing purposes or just to create more modular code. StructureMap is such a framework for C#, but there are others, such as Spring.NET.
Sounds like you want to be using Unit Testing Frameworks and/or Mocking Frameworks.
As a general rule, you shouldn't be writing additional queries to test the query has worked as expected on the database as these themselves will require development and testing.
Depending on the database you're writing to, you may be able to get the number of rows affected on the database (take a look at ##rowcount for SQL Server). But again, you're adding additional code just to do testing which should really be a separate activity.
I am still having a issue getting over a small issue when it comes to TDD.
I need a method that will get a certain record set of filtered data from the data layer (linq2SQL). Please note that i am using the linq generated classes from that are generated from the DBML. Now the problem is that i want to write a test for this.
do i:
a) first insert the records in the test and then execute the method and test the results
b) use data that might be in the database. Not to keen on this logic cause it could cause things to break.
c) what ever you suggest?
You should choose option a).
A unit test should be repeatable and has to be fully under your control. So for the test to be meaningful it is absolutely necessary that the test itself prepares the data for its execution - only this way you can rely on the test outcome.
Use a testdatabase and clean it each time you run the tests. Or you might try to create a mock object.
When I run tests using a database, I usually use an in-memory SQLite database.
Using an in memory db generally makes the tests quicker.
Also it is easy to maintain, because the database is "gone" after you close the connection to it.
In the test setup, I set up the db connection and I create the database schema.
In the test, I insert the data needed by the test. (your option a))
In the test teardown, I close the connection to the db.
I used this approach successfully for my NHibernate applications (howto 1 | howto 2 + nice summary), but I'm not that familiar with Linq2SQL.
Some pointers on running SQLite and Linq2SQL are on SO (link 1 | link 2).
Some people argue that a test using a database isn't a unit test. Regardless, I belief that there are situations where you want automated testing using a database:
You can have an architecture / design, where the database is hard to mock out, for instance when using an ActiveRecord pattern, or when you're using Linq2SQL (although there is an interesting solution in one of the comments to Peter's answer)
You want to run integration tests, with the complete system of application and database
What I have done in the past:
Start a transaction
Delete all data from all the tables in the database
Setup the reference data all your tests need
Setup the test data you need in database tables
Run your test
Abort the transaction
This works well provided your database does not have much data in it, otherwise it is slow. So you will wish to use a test database. If you have a test database that is well controlled, you could just run the test in the transaction without the need to delete all data first.
Try to design your system, so you get mock the data access layer for most of your tests. It is valid (and often useful) to unit test database code, however the unit tests for your other code should not need to touch the database.
You should consider if you would get more benefits from “end to end” system tests, with unit tests only for your “logic” code. This depend to an large extent on other factors within the project.