JonPSmith / EfCore.TestSupport

Tools for helping in unit testing applications that use Entity Framework Core
https://www.thereformedprogrammer.net/new-features-for-unit-testing-your-entity-framework-core-5-code/
Other
352 stars 53 forks source link

AppSettings.GetUniqueDatabaseConnectionString not always unique #16

Closed davisnw closed 5 years ago

davisnw commented 5 years ago

GetUniqueDatabaseConnectionString doesn't always return a unique result.

For example, if I need to create two databases in a single test, then the default behavior won't generate two distinct connection strings. This is easily worked around by adding extra "jitter" to the test name in addition to e,g, $"{nameof(MyTestMethod)}_1" and $"{nameof(MyTestMethod)}_2"

A bit more significant concern is that if for some reason a test database fails to get cleaned up at the end of execution, GetUniqueDatabaseConnectionString will return the same connection string the next test run, possibly causing the test to fail in exciting and exotic ways.

This can also be worked around by adding extra code to check for the existence of the database before executing the rest of the test - but that is extra code to write, or by adding uniqueness "jitter" to the testName, e.g. this.GetUniqueDatabaseConnectionString($"{nameof(MyTestMethod)}_{Guid.NewGuid()}");

However, it caught me by surprise the first time that happened, and I wonder if the utility should provide out-of-the-box support for generating truly unique database names, or perhaps ensuring that the database doesn't already exist before returning the "unique" connection string?

Or perhaps just update the documentation at https://github.com/JonPSmith/EfCore.TestSupport/wiki/3b.-Creating-connection-strings#the-getuniquedatabaseconnectionstring-extention-method to more clearly indicate that a test database left over from a previous run may cause issues?

JonPSmith commented 5 years ago

Hi @davisnw,

Its worth me explaining why I do various things:

  1. The GetUniqueDatabaseConnectionString returns a connection string which is unique to the class. That is useful because xUnit runs all test classes in parallel and you need at least one unique database per test class to stop multiple unit tests accessing a database at the same time.
  2. GetUniqueDatabaseConnectionString, and the more complex CreateUniqueClassOptions simply provide you with a way to access a database. It is up to you to create the database using the normal EF Core test commands (see this doc about delete/create).
  3. Typical use of databases in unit tests is to have a database that you reuse, with any delete/create as necessary. You can of course create new, unique databases each time but if you can reuse a database, with any require wipe/delete, then your unit tests will run quicker. You also have less test databases to clear up.
  4. If you use GetUniqueDatabaseConnectionString, CreateUniqueClassOptions etc. then you can use the DeleteAllUnitTestDatabases to delete all your test databases.

I have updated the docs to explain why, be default, it creates a database name unique to the object you provide, which is normally the test class - see point 1.