Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create InMemoryProvider for unittesting #28

Open
vojtechrojicek opened this issue Jul 15, 2019 · 0 comments
Open

Create InMemoryProvider for unittesting #28

vojtechrojicek opened this issue Jul 15, 2019 · 0 comments
Labels
enhancement New feature or request up-for-grabs

Comments

@vojtechrojicek
Copy link

It would be nice to have some type of InMemoryProvider where I can pass data and I will be able to mock IDatabase.
Right now its almost impossible to mock it.

We created some quick solution, that should be refactored and maybe used.

It provide get methods. It is able to returns all data and for other (Any, Where, ...) it returns just first entity. Other methods are NotImplemented yet.

/// <summary>
/// Class for mocking KORM IDatabase
/// </summary>
public static class InMemoryDatabaseHelper
{
    /// <summary>
    /// Create simple in memory mock of KORM with given data.
    /// </summary>
    /// <typeparam name="TData">Type of data.</typeparam>
    /// <param name="data">Data to be mocked.</param>
    /// <returns></returns>
    public static IDatabase BuildInMemory<TData>(IEnumerable<TData> data)
        => Database.Builder.UseConnection("memory", "test").UseQueryProviderFactory(CreateProvider(data)).Build();

    private static InMemoryQueryProviderFactory<TData> CreateProvider<TData>(IEnumerable<TData> data)
        => new InMemoryQueryProviderFactory<TData>(data);
}

internal class InMemoryQueryProviderFactory<TData> : IQueryProviderFactory
{
    private readonly IEnumerable<TData> _data;

    public InMemoryQueryProviderFactory(IEnumerable<TData> data)
    {
        _data = data;
    }

    public KORM.Query.IQueryProvider Create(DbConnection connection, IModelBuilder modelBuilder, IDatabaseMapper databaseMapper)
    {
        return new InMemoryQueryProvider<TData>(_data);
    }

    public KORM.Query.IQueryProvider Create(ConnectionStringSettings connectionString, IModelBuilder modelBuilder, IDatabaseMapper databaseMapper)
    {
        return new InMemoryQueryProvider<TData>(_data);
    }
}

internal class InMemoryQueryProvider<TData> : KORM.Query.IQueryProvider
{
    private const string NotImplementedError = "This method was not implemented yet. If you need to mock it please implement it by yourself.";
    private readonly IEnumerable<TData> _data;

    public InMemoryQueryProvider(IEnumerable<TData> data)
    {
        _data = data;
    }

    public IEnumerable<T> Execute<T>(IQuery<T> query) => _data.Cast<T>();

    public IQueryable CreateQuery(Expression expression) => new InMemoryQuery<TData>(this, _data, expression);

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression) => (IQueryable<TElement>)CreateQuery(expression);

    public object Execute(Expression expression) => _data.FirstOrDefault();

    public TResult Execute<TResult>(Expression expression) => (TResult)Execute(expression);

    #region NotImplemented
    public DbProviderFactory DbProviderFactory => throw new NotImplementedException(NotImplementedError);

    public ITransaction BeginTransaction(IsolationLevel isolationLevel) => throw new NotImplementedException(NotImplementedError);

    public IBulkInsert CreateBulkInsert() => throw new NotImplementedException(NotImplementedError);

    public IBulkUpdate CreateBulkUpdate() => throw new NotImplementedException(NotImplementedError);

    public IIdGenerator CreateIdGenerator(string tableName, int batchSize) => throw new NotImplementedException(NotImplementedError);

    public void Dispose() => throw new NotImplementedException(NotImplementedError);

    public Task ExecuteInTransactionAsync(Func<Task> action)
        => throw new NotImplementedException(NotImplementedError);

    public int ExecuteNonQuery(string query)
        => throw new NotImplementedException(NotImplementedError);

    public int ExecuteNonQuery(string query, CommandParameterCollection parameters)
        => throw new NotImplementedException(NotImplementedError);

    public Task<int> ExecuteNonQueryAsync(string query)
        => throw new NotImplementedException(NotImplementedError);

    public Task<int> ExecuteNonQueryAsync(string query, params object[] paramValues)
        => throw new NotImplementedException(NotImplementedError);

    public Task<int> ExecuteNonQueryAsync(string query, CommandParameterCollection parameters)
        => throw new NotImplementedException(NotImplementedError);

    public int ExecuteNonQueryCommand(IDbCommand command)
        => throw new NotImplementedException(NotImplementedError);

    public Task<int> ExecuteNonQueryCommandAsync(DbCommand command)
        => throw new NotImplementedException(NotImplementedError);

    public object ExecuteScalar<T>(IQuery<T> query)
        => throw new NotImplementedException(NotImplementedError);

    public object ExecuteScalarCommand(IDbCommand command)
        => throw new NotImplementedException(NotImplementedError);

    public Task<object> ExecuteScalarCommandAsync(DbCommand command)
        => throw new NotImplementedException(NotImplementedError);

    public TResult ExecuteStoredProcedure<TResult>(string storedProcedureName)
        => throw new NotImplementedException(NotImplementedError);

    public TResult ExecuteStoredProcedure<TResult>(string storedProcedureName, CommandParameterCollection parameters)
        => throw new NotImplementedException(NotImplementedError);

    public DbCommand GetCommandForCurrentTransaction() => throw new NotImplementedException(NotImplementedError);

    public void SetParameterDbType(DbParameter parameter, string tableName, string columnName)
        => throw new NotImplementedException(NotImplementedError);

    public bool SupportsIdentity() => throw new NotImplementedException(NotImplementedError);

    public bool SupportsPrepareCommand() => throw new NotImplementedException(NotImplementedError);
    #endregion
}

internal class InMemoryQuery<TData> : IQueryable<TData>
{
    private readonly IEnumerable<TData> _data;

    public Type ElementType => typeof(TData);

    public Expression Expression { get; private set; }

    public System.Linq.IQueryProvider Provider { get; private set; }

    public InMemoryQuery(InMemoryQueryProvider<TData> queryProvider, IEnumerable<TData> data)
    {
        Provider = queryProvider;
        Expression = data.AsQueryable().Expression;
        _data = data;
    }

    public InMemoryQuery(InMemoryQueryProvider<TData> queryProvider, IEnumerable<TData> data, Expression expression)
    {
        Provider = queryProvider;
        Expression = expression;
        _data = data;
    }

    public IEnumerator<TData> GetEnumerator() => _data.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

Mock IDatabase in UnitTests:

var data = new List<Note>() { new Note() { Id = 1, Note = "Hello in memory KORM." }};
var database = InMemoryDatabaseHelper.BuildInMemory(data);

public class Note {
  public int Id { get; set; }
  public string Note { get; set; }
}
@Burgyn Burgyn added enhancement New feature or request up-for-grabs labels Jul 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request up-for-grabs
Projects
None yet
Development

No branches or pull requests

2 participants