ZZZSharePoint
ZZZSharePoint

Reputation: 1351

Best practice for unit test cases

I am using the xUnit.net test framework and in each unit test I have certain steps which I am doing in each case. I would like to know if there is a way I call this method once before my unit case starts and also call when all unit test cases has been executed.

For example: In the scenario below I have two unit cases and in each case I am creating a local DB, populating it with data and then running my test and once it is done I am calling method to delete the DB. This I am doing in each test case. Instead of multiple creation I would like to create once and populate once and then delete db once all test case has been executed. It is important for me to delete what I have created as the test cases has certain cases which will fail if Database is not created when the tests are executed.

[Fact]
public void UnitCase1()
{
   CreateDb();
   UploadData();
   ...//My set of operation to test this case
   ...//Assert
   DeleteDb()
}

[Fact]
public void UnitCase2()
{
   CreateDb();
   UploadData();
   ...//My set of operation to test this case
   ...//Assert
   DeleteDb()
}

Editing after Answer from Eric:(I tried but its not working)

public class CosmosDataFixture : IDisposable
    {
        public static readonly string CosmosEndpoint = "https://localhost:8081";
        public static readonly string EmulatorKey = "Mykey";
        public static readonly string DatabaseId = "Databasename";
        public static readonly string RecordingCollection = "collectionName";
        string Root = Directory.GetParent( Directory.GetCurrentDirectory() ).Parent.Parent.FullName;
        DocumentClient client = null;

        public void ReadAllData( DocumentClient client )
        {
           //reading document code
        }

        public void ReadConfigAsync()
        {
            client = new DocumentClient( new Uri( CosmosEndpoint ), EmulatorKey,
                 new ConnectionPolicy
                 {
                     ConnectionMode = ConnectionMode.Direct,
                     ConnectionProtocol = Protocol.Tcp

                 } );
        }
 public void CreateDatabase()
        {// create db code
        }
private void DeleteDatabase()
        {
          // delete db code
        }
     public CosmosDataFixture()
        {
            ReadConfigAsync();
            CreateDatabase();
            ReadAllData( client );

        }

        public void Dispose()
        {
            DeleteDatabase();
        }
    }
public class CosmosDataTests : IClassFixture<CosmosDataFixture>
    {
        CosmosDataFixture fixture;

        public CosmosDataTests( CosmosDataFixture fixture )
        {
            this.fixture = fixture;
        }

        [Fact]
        public async Task CheckDatabaseandCollectionCreation()
        {          
            List<string> collectionName = new List<string>();
            var uri = UriFactory.CreateDatabaseUri(DatabaseId);// don't get DatabaseId or client says does not exist in current context
            var collections = await client.ReadDocumentCollectionFeedAsync( uri );
            foreach( var collection in collections )
            {
                collectionName.Add( collection.Id);
            }
                
        }

Upvotes: 2

Views: 1151

Answers (3)

Mark Seemann
Mark Seemann

Reputation: 233150

As other people have pointed out, such tests are in mainstream parlance not unit tests, but rather integration tests. xUnit.net is a fine framework for those kinds of tests, though, so apart from the semantic distinction, it makes little technical difference.

Apart from setting up the database in the test class' constructor and tearing it down in Dispose, as outlined by Eric Schaefer, you can also use xUnit.net's BeforeAfterTestAttribute. You'll then override Before to set up the database, and override After to tear it down:

public class UseDatabaseAttribute : BeforeAfterTestAttribute
{
    public override void Before(MethodInfo methodUnderTest)
    {
        CreateDb();
        UploadData();

        base.Before(methodUnderTest);
    }

    public override void After(MethodInfo methodUnderTest)
    {
        base.After(methodUnderTest);
        DeleteDb();
    }
}

You can then annotate either each test method, or the entire test class with the attribute. I usually just annotate the class:

[UseDatabase]
public class DbTests
{
    // Tests go here...
}

Since tests that use a database interact with a shared resource (the database), they can't easily run in parallel. By default, xUnit.net runs tests in parallel, so you may want to disable that. You can do it by adding an xunit.runner.json file:

{
  "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
  "parallelizeTestCollections": false
}

Finally, at least if you're using SQL Server, connection pooling will prevent you from deleting the database. You can either turn off connection pooling for your tests, or forcibly close other connections before teardown.

Upvotes: 2

EricSchaefer
EricSchaefer

Reputation: 26340

That's what [SetUp] and [TearDown] are for in NUnit. They are run right before and right after each test case, respectively. In xUnit you would usually implement a default constructor and IDisposable.

For example:


public TestClass()
{
   CreateDb();
   UploadData();
}


public void Dispose()
{
   DeleteDb()
}

[Fact]
public void UnitCase1()
{
   ...//My set of operation to test this case
   ...//Assert
}

[Fact]
public void UnitCase2()
{
   ...//My set of operation to test this case
   ...//Assert
}

Upvotes: 3

sagape4
sagape4

Reputation: 36

In my experience in Testing, I see 2 points here: 1-If you are checking that the data from the DB to another point in the program is being transmited correctly, that is Integration Testing, and it should be out of scope in the Unit Testing Plan, make sure that the responsabilities of a Unit Tester are clear where you work as there are some companies which avoid Integration Testing levels by assuming that if Functional Testing is 'OK', integrations should be too.

2- You mention at the end

It is important for me to delete what I have created as the test cases has certain cases which will fail if Database is not created when the tests are executed

but

I would like to create once and populate once and then delete db once all test case has been executed.

If I understand correctly, you need to do it for each Test Case as not all test cases are checking the same scenario, so it looks like those statements are the real problem here.

To answer your question, as it seems like you want to automate the process with minimum maintenance for the next releases, and I also know how the work environment tend to corner you to do some stuff that shouldn't be, I could think of a Preconditions Function and a Postcondition one, where you do it once and that's it.

If that is not possible for whatever reason, try to create another Test Case at the beginning (like Test Case 0) where you create and populate the DB (if apply, or separate it if needed) and another one at the end where you delete it.

I'm not familiar with the framework you are using, but I have a lot of experience in Testing, opening test levels and automating tasks, and hope that my answer could be of some help.

Upvotes: 0

Related Questions