0

I want to write some unit tests for a method. However, the method references my entity framework. Here is a heavily contrived example of the method I want to test:

public int GetNumberWithName(string name, NWRevalDatabaseEntities entities)
{
    int number = (from n in entities.TableOfNumbers
                    where n.Name == name
                    select n).First();

    return number;
}

The question:

Is there a way for me to instantiate a NWRevalDatabaseEntities object in my testing class without giving it a viable database connection, so all the tables are empty, and then just inserting the entities needed for the test, and never persisting them to a database?

The store for NWRevalDatabaseEntities is a SQLite database, and the auto generated constructors available are:

/// <summary>
/// Initializes a new NWRevalDatabaseEntities object using the connection string found in the 'NWRevalDatabaseEntities' section of the application configuration file.
/// </summary>
public NWRevalDatabaseEntities() : base("name=NWRevalDatabaseEntities", "NWRevalDatabaseEntities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

/// <summary>
/// Initialize a new NWRevalDatabaseEntities object.
/// </summary>
public NWRevalDatabaseEntities(string connectionString) : base(connectionString, "NWRevalDatabaseEntities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

/// <summary>
/// Initialize a new NWRevalDatabaseEntities object.
/// </summary>
public NWRevalDatabaseEntities(EntityConnection connection) : base(connection, "NWRevalDatabaseEntities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

All of which require a connection or connection string (or uses the stored connection string).

If this is not possible, I will look into creating an in-memory SQLite database and then feed that connection to the NWRevalDatabaseEntities constructor. However, this seems like it would be much slower (since it hits the database engine) and unit testing should be fast, and also, will require me to get the database definition code into my application, where it was not previously needed.

I know testing anything with entity frameworks usually go to integration testing, not unit testing. However, these tests don't really test integration - the database query is incredibly simplistic and might as well have been against an array - I just want to check that the right selection of query is made by my method.

1 Answer 1

2

Is there a way for me to instantiate a NWRevalDatabaseEntities object in my testing class without giving it a viable database connection, so all the tables are empty, and then just inserting the entities needed for the test, and never persisting them to a database?

No.

However, this seems like it would be much slower (since it hits the database engine) and unit testing should be fast, and also, will require me to get the database definition code into my application, where it was not previously needed.

But your method is dependent on EF so you should test that it work with EF = with database.

I know testing anything with entity frameworks usually go to integration testing, not unit testing. However, these tests don't really test integration - the database query is incredibly simplistic and might as well have been against an array - I just want to check that the right selection of query is made by my method.

Simplistic or not, it is a database query using Linq-to-entities. It is not an array query using Linq-to-objects. This query is also very simplistic: entities.TableOfNumbers.Last() - it works on array but doesn't work with EF. If you don't want to test your query, separate it from the method you want to test:

public int GetNumberWithName(string name, NWRevalDatabaseEntities entities)
{
    int number = ExecuteQuery(entities, Name);
    return number;
}

Now you just need to find how to replace ExecuteQuery method for test. You can make it protected virtual and override it for test because the only thing you want to test is that it receives correct Name parameter and that your GetNumberWithName returns the same number it received from ExecuteQuery.

Now you just need to write integration test for ExecuteQuery to verify that Linq query works with EF.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for a very thorough answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.