To run RDMP tests install Sql Server Localdb then run dotnet test ./scripts/run-all-tests.proj -c Release -p:BuildInParallel=false
Tests in RDMP are split between Unit, User Interface and Database tests.
Many create tables/records in the test database or files on disk therefore parallel test execution is not recommended.
Unit tests are tests which do not require a database or for any UI code to run. These either have no base class or inherit from UnitTests
(allows you to create RDMP platform objects e.g. Catalogue
).
public class CatalogueTests : UnitTests
{
[Test]
public void Test_GetObjects_Catalogue()
{
Catalogue catalogueWithId = new Catalogue(Repository, "bob");
Catalogue[] catas = Repository.GetAllObjects<Catalogue>();
Assert.IsTrue(catas.Length > 0);
catalogueWithId.DeleteInDatabase();
}
}
Example Unit Test
User interface tests which confirm behaviours of RDMP client user interfaces e.g. CatalogueUI
. These tests create instances of Forms/Controls but do not actually show them (we do not use UI automation).
You can write new user interface tests by inheriting UITests
and specifying a UITimeoutAttribute
on the Test (this prevents messageboxes blocking the test indefinetly in failure conditions and ensures that an STA thread is used.)
public class CatalogueUITests : UITests
{
[Test, UITimeout(20000)]
public void Test_CatalogueUI_NormalState()
{
//Get a new platform object
var cata = WhenIHaveA<Catalogue>();
//Get an instance of the UI
var ui = AndLaunch<CatalogueUI>(cata);
//when I type text
ui._scintillaDescription.Text = "amagad zombies";
//my class should get the typed text but it shouldn't be saved into the database yet
Assert.AreEqual("amagad zombies", cata.Description);
Assert.AreEqual(ChangeDescription.DatabaseCopyDifferent, cata.HasLocalChanges().Evaluation);
//get the save button
var saver = ui.GetObjectSaverButton();
//when I save
saver.Save();
//my class should have no changes (vs the database) and should have the proper description
Assert.AreEqual(ChangeDescription.NoChanges, cata.HasLocalChanges().Evaluation);
Assert.AreEqual("amagad zombies", cata.Description);
//No errors of any type should have been displayed
AssertNoErrors(ExpectedErrorType.Any);
}
Example User Interface Test
The RDMP client requires an Sql Server instance for storing platform metadata objects (Catalogue
, Project
etc). its primary purpose is to query / manage SQL datasets (for linkage, extraction etc). Database tests exist to test this functionality.
The easiest way to achieve this is to install 'SQL Server Express LocalDB'.
You can install SQL Server Express LocalDB via the Visual Studio Installer. Alternatively, if you are running on linux you can install sql server express.
If you are using LocalDB then your server will be called (localdb)\MSSQLLocalDB
. If you have manually installed the full version of SQL Server Express then it is likely to be called localhost\sqlexpress
or just localhost
.
If you are not using LocalDb you will have to update TestDatabases.txt to specify the correct Server:
. Running on linux also requires entering the container's Username:
and Password:
options. On windows integrated security will automatically handle authentication based on your user account.
The first time you run dotnet test
RDMP will create the testing databases listed in TestDatabases.txt provided that:
- The server exists and can be connected to
- The Prefix listed contains 'TEST' (case insensitive).
If this process fails or you need to manually recreate them then this can be done with the RDMP command line. You can either run it from the repository or fetch the binary from Github Releases.
cd ./Tools/rdmp/
dotnet run -- install "(localdb)\MSSQLLocalDB" TEST_ -D
If you have a testing environment with an Oracle, Postgres and\or MySql server instance then you can enable running these tests too by entering the connection strings into TestDatabases.txt. If you do not define a connection string then these tests will be marked Inconclusive
when run.
WARNING: DatabaseTests will delete the contents of the TEST_ databases before each test is run and some will create temporary databases/tables during runtime, therefore it is important that you do not use a production server for integration testing
You can write new database tests by inheriting from DatabaseTests
or one of the Scenarios (e.g. TestsRequiringAnExtractionConfiguration
).
public class MyTests : DatabaseTests
{
[Test]
public void Test1()
{
var cata = new Catalogue(CatalogueRepository,"My Test Cata");
Assert.IsTrue(cata.Exists());
}
}
Example Database Test
If you want to run your test against multiple database types (Oracle / MySql etc) then you should use TestCase
and call GetCleanedServer
to obtain a cross platform object that represents the scratch database.
public class MyTests : DatabaseTests
{
[TestCase(DatabaseType.MicrosoftSQLServer)]
[TestCase(DatabaseType.Oracle)]
[TestCase(DatabaseType.MYSQLServer)]
public void Test2(DatabaseType type)
{
var database = GetCleanedServer(type);
Assert.IsTrue(database.Exists());
Assert.IsEmpty(database.DiscoverTables(true));
Assert.IsNotNull(database.GetRuntimeName());
}
}
If you want to test a system running under a database user account with limited access rights you can use DatabaseTests.SetupLowPrivilegeUserRightsFor
. You will have to create the user account yourself and configure connect etc privileges.
public class MyTests : DatabaseTests
{
[TestCase(DatabaseType.MicrosoftSQLServer)]
[TestCase(DatabaseType.Oracle)]
[TestCase(DatabaseType.MYSQLServer)]
public void TestReadDataLowPrivileges(DatabaseType type)
{
var database = GetCleanedServer(type);
//create a table on the server
var dt = new DataTable();
dt.Columns.Add("MyCol");
dt.Rows.Add("Hi");
dt.PrimaryKey = new[] {dt.Columns[0]};
var tbl = database.CreateTable("MyTable", dt);
//at this point we are reading it with the credentials setup by GetCleanedServer
Assert.AreEqual(1, tbl.GetRowCount());
Assert.AreEqual(1, tbl.DiscoverColumns().Count());
Assert.IsTrue(tbl.DiscoverColumn("MyCol").IsPrimaryKey);
//create a reference to the table in RMDP
TableInfo tableInfo;
ColumnInfo[] columnInfos;
Import(tbl, out tableInfo, out columnInfos);
//setup credentials for the table in RDMP (this will be Inconclusive if you have not enabled it in TestDatabases.txt
SetupLowPrivilegeUserRightsFor(tableInfo,TestLowPrivilegePermissions.Reader);
//request access to the database using DataLoad context
var newDatabase = DataAccessPortal.GetInstance().ExpectDatabase(tableInfo, DataAccessContext.DataLoad);
//get new reference to the table
var newTbl = newDatabase.ExpectTable(tableInfo.GetRuntimeName());
//the credentials should be different
Assert.AreNotEqual(tbl.Database.Server.ExplicitUsernameIfAny, newTbl.Database.Server.ExplicitUsernameIfAny);
//try re-reading the data
Assert.AreEqual(1, newTbl.GetRowCount());
Assert.AreEqual(1, newTbl.DiscoverColumns().Count());
Assert.IsTrue(newTbl.DiscoverColumn("MyCol").IsPrimaryKey);
//low priority user shouldn't be able to drop tables
Assert.That(newTbl.Drop,Throws.Exception);
//normal testing user should be able to
tbl.Drop();
}
}