Nigel
Nigel

Reputation: 23

Unit Testing MongoDB WriteOneAsync() Fails to create document

I'm a tad perplexed writing a unit test to test a MongoDB WriteOneAsync(). I have tried running the unit test on a MongoDB example that writes a document to the MongoDB but it is failing to write the document to the database.

Below is my code. I tried awaiting mc.savetomongo(); but it cannot await a void.

This is just an example I put together to demo the problem. My actual code uses a an interface and data layer but same problem.

I should say that the code works fine if I call savetomongo() from within its own project class or from a form project. The problem seems to only exists when unit testing.

Any help woiuld be massivly appreciated!

Many thanks

I have a unit test project as follows,

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using mongotestclass;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public async void TestMethod1()
        {
            Mongoclass mc = new Mongoclass();

           mc.savetomongo();
        }
    }
}

I also have a seperate class project containing the following.

using MongoDB.Bson;
using MongoDB.Driver;
using System;

namespace mongotestclass
{
    public class Mongoclass
    {
        protected static IMongoClient _client;


    protected static IMongoDatabase _database;

        public async void savetomongo()
        {
            Uri con;
            Uri.TryCreate("mongodb://" + "DESKTOP-263RHTL:27017", UriKind.Absolute, out con);

            _client = new MongoClient(new MongoClientSettings
            {
                ConnectTimeout = new TimeSpan(0, 0, 0, 5, 0),
                Server = new MongoServerAddress(con.Host, con.Port)
            });

            _database = _client.GetDatabase("SchemaTest3");

            var document = new BsonDocument
            {
                { "address" , new BsonDocument
                    {
                        { "street", "2 Avenue" },
                        { "zipcode", "10075" },
                        { "building", "1480" },
                        { "coord", new BsonArray { 73.9557413, 40.7720266 } }
                    }
                },
                { "borough", "Manhattan" },
                { "cuisine", "Italian" },
                { "grades", new BsonArray
                    {
                        new BsonDocument
                        {
                            { "date", new DateTime(2014, 10, 1, 0, 0, 0, DateTimeKind.Utc) },
                            { "grade", "A" },
                            { "score", 11 }
                        },
                        new BsonDocument
                        {
                            { "date", new DateTime(2014, 1, 6, 0, 0, 0, DateTimeKind.Utc) },
                            { "grade", "B" },
                            { "score", 17 }
                        }
                    }
                },
                { "name", "Vella" },
                { "restaurant_id", "41704620" }
            };

            var collection = _database.GetCollection<BsonDocument>("restaurants");
            await collection.InsertOneAsync(document);
        }
    }
}

Upvotes: 1

Views: 380

Answers (1)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149558

The problem lays in the fact that your test ends prematurely, due to the fact that you're not awaiting on any of the asynchronous tasks. Thus, you have a race condition between the insertion of the document and the termination of the test.

What you actually need to do is expose an async Task operation, instead of async void, which will allow you to await up the call chain of your test:

public Task SaveToMongoAsync()
{
    Uri con;
    Uri.TryCreate("mongodb://" + "DESKTOP-263RHTL:27017", UriKind.Absolute, out con);

    _client = new MongoClient(new MongoClientSettings
    {
        ConnectTimeout = new TimeSpan(0, 0, 0, 5, 0),
        Server = new MongoServerAddress(con.Host, con.Port)
    });

    _database = _client.GetDatabase("SchemaTest3");

    var document = new BsonDocument
    {
        { "address" , new BsonDocument
            {
                { "street", "2 Avenue" },
                { "zipcode", "10075" },
                { "building", "1480" },
                { "coord", new BsonArray { 73.9557413, 40.7720266 } }
            }
        },
        { "borough", "Manhattan" },
        { "cuisine", "Italian" },
        { "grades", new BsonArray
            {
                new BsonDocument
                {
                    { "date", new DateTime(2014, 10, 1, 0, 0, 0, DateTimeKind.Utc) },
                    { "grade", "A" },
                    { "score", 11 }
                },
                new BsonDocument
                {
                    { "date", new DateTime(2014, 1, 6, 0, 0, 0, DateTimeKind.Utc) },
                    { "grade", "B" },
                    { "score", 17 }
                }
            }
        },
        { "name", "Vella" },
        { "restaurant_id", "41704620" }
    };

    var collection = _database.GetCollection<BsonDocument>("restaurants");
    return collection.InsertOneAsync(document);
}

And now make your test async Task as well and await in it:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public async Task TestMongoInsertionAsync()
    {
        Mongoclass mc = new Mongoclass();
        await mc.SaveToMongoAsync();
    }
}

As a side note I would improve this test, and actually return a value you can assert on in your test to make sure the document was correctly inserted.

Upvotes: 1

Related Questions