Unit of work repository pattern for static class - c#

Task assigned to me is to refactor a code but should't modify static access modifier of class. I am trying to implement service layer , unit of work , repository pattern . static repository code is below , how can i implement unit of work and repository pattern for a static class? i like to implement a solution applying solid principles and unit testable application.
static class
using System;
using System.Data.SqlClient;
namespace Contoso
{
public static class UsersRepository
{
private static string ConnectionString = #"Data Source=(local); Database=Users;User Id=sa;Password=password;";
public static User Load(int userId)
{
User user = new User();
SqlConnection connection = new SqlConnection(ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM Users WHERE UserId = " + userId,
connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
user.Name = reader["Name"].ToString();
user.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString());
user.Country = reader["Country"].ToString();
}
connection.Close();
return user;
}
}
}

How can i implement unit of work and repository pattern for a static class?
You can leverage the fact that whenever someone calls the code here, they do so via a public entry point. This means that when the caller first enters the class (via said public method), you create a unit of work and dispose of it only when that same method returns a value to the caller (or simply ends).
Something along the lines of:
public static class MyClass
{
public static User LoadUser(int userId)
{
using (var uow = new UnitOfWork())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
Essentially, every public method should create, use and dispose of a single unit of work instance. This ensures two things:
Concurrent calls use their own separate unit of work.
No unit of work will ever linger in-memory after the entry method has finished.
This does get trickier when you start using async programming, but I'm omitting that consideration since you never mentioned it either.
i like to implement a solution applying solid principles and unit testable application
It gets slightly trickier when you deal with dependency injection. Static classes do not have an injectable constructor (note: they do have a constructor, but they don't allow for constructor arguments).
So injecting your dependency is going to be... atypical. One solution I can think of is to explicitly set the kernel (I am using NInject here as a matter of example):
public static class MyClass
{
public static IKernel Kernel { get; set; }
public static User LoadUser(int userId)
{
using (var uow = Kernel.Get<IUnitOfWork>())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
How you set the kernel (either by setting it explicitly or assigning it a default value directly) is up to you.
Without NInject or any similar library, you could achieve dependency injection using a Func<IUnitOfWork> as your factory method to create a unit of work on demand:
public static class MyClass
{
public static Func<IUnitOfWork> CreateUnitOfWork { get; set; }
public static User LoadUser(int userId)
{
using (var uow = CreateUnitOfWork())
{
DoSomething(uow);
var user = uow.UserRepository.GetById(userId);
return user;
}
}
}
Again, how you set the factory method's content is up to you, e.g.:
MyClass.CreateUnitOfWork = () => new UnitOfWork();

Related

Cannot access appsettings.json from class library

I have been following this tutorial in order to get access to my appsettings.json from my MVC project inside my class library.
geek-tutorial
I have a class as such in my class library
using dapper;
public class SqlDataAccess : IConfigManager
{
private readonly IConfiguration _configuration;
public SqlDataAccess(IConfiguration configuration)
{
this._configuration = configuration;
}
public List<T> LoadData<T>(string sql)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Query<T>(sql).ToList();
}
}
public int SaveData<T>(string sql, T data)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Execute(sql, data);
}
}
public string GetConnectionString(string connectionName = "URLShortnerDB")
{
return this._configuration.GetConnectionString(connectionName);
}
}
Interface:
public interface IConfigManager
{
string GetConnectionString(string connectionName);
}
I have added services.AddSingleton<IConfigManager, SqlDataAccess>(); in my mvc startup.cs
However now I would like to use my SqlDataAccess class and call methods from another class e.g:
public static class ShortUrlProcessor
{
public static ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = SqlDataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
However SqlDataAccess is not instantiated, and in order to do var _sqldataaccess = SqlDataAccess() I need to pass in a parameter as defined in the constructor of the class. I do not know what to pass in? I do not have any IconfigurationManager in this ShortUrlProcessor class. I understand the reason of doing this is dependancy injection, however I am still not grasping how this all works?
You're very close, but you need to fix a few things. SqlDataAccess implements IConfigManager. Why? What's that providing? Instead, you should have it implement an interface that allows it to expose the functionality other classes depend on.
public interface ISqlDataAccess
{
List<T> LoadData<T>(string sql);
int SaveData<T>(string sql, T data);
}
Change your SqlDataAccess class to implement this interface...
public class SqlDataAccess : ISqlDataAccess
And of course, wire this up with your DI container.
services.AddTransient<ISqlDataAccess, SqlDataAccess>();
Now, any class that needs to run SQL can take a dependency on the ISqlDataAccess interface, utilizing constructor injection to get an instance of ISqlDataAccess. Since we've told the DI container to provide a SqlDataAccess instance when the ISqlDataAccess dependency is present, it will all wire up nicely in your app.
Then we have the issue with ShortUrlProcessor. You declared that class as static. That's bad, because it makes it difficult for it to use constructor injection to get its dependencies, and any other class that needs to invoke its methods has to do so directly, rather than via an abstraction. That violates the Dependency Inversion Principle of SOLID. And since we should always strive to write SOLID code because of the maintainability and testability, we need to fix that.
public class ShortUrlProcessor : IShortUrlProcessor
{
readonly ISqlDataAccess _dataAccess;
public ShortUrlProcessor(ISqlDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = _dataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
And we'll need an interface so other classes don't have to depend directly on ShortUrlProcessor...
public interface IShortUrlProcessor
{
ShortURLModel GetOriginalURL(string shortUrl);
}
And of course, we need to register it with our DI container.
services.AddTransient<IShortUrlProcessor, ShortUrlProcessor>();
Then any class that needs to access the functionality of ShortUrlProcessor can do so via the abstraction IShortUrlProcessor. You mentioned you have a controller calling this, so let's wire that up too.
public class MyController()
{
readonly IShortUrlProcessor _shortUrlProcessor;
public MyController(IShortUrlProcessor shortUrlProcessor)
{
_shortUrlProcessor = shortUrlProcessor;
}
public ActionResult SomeActionMethod()
{
var model = _shortUrlProcessor.GetOriginalURL("asdf");
return View(model);
}
}
We don't have to create an interface for the controller, because the controller will be called by the framework. And we don't have to wire up the controller with the DI container, because the framework handles that for us.
By doing all this, we can easily test individual methods in isolation. There's still some improvements to be made (the SQL Injection attack I mentioned in the comments needs to be fixed), but it's a good step in the right direction.

Unit testing database using EF

How does one unit test a service which connects to a database?
I have a playerRepository class in data access layer, which interacts with the database directly, and a playerService class in business layer which creates an instance of playerRepository and services random stuff like - deleting player, saving player, getting all players, getting the player by id/name yadda yadda.
I want to unit test the playerService without using the real database, but using in-memory database provided with EF.
The problem is, I'm having trouble figuring out how to set it up.
I have a PlayerContext : DbContext class, which is used as a model to code-first (done this part via tutorial on EF). And I have to add a parameter to constructor DbContextOptionsBuilder<PlayerContext>, but I don't know where to begin. I don't know how and where to setup the connection string, where does the "default" database store itself.
I want to do this by using EF without NSubstitute or Moq, I'm doing this to learn how it's done without using other frameworks except for EF.
public class PlayerContext : DbContext
{
public PlayerContext() : base()
{
}
public DbSet<Player> Players { get; set; }
}
public class Player
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int DciNumber { get; set; }
}
I'm using visual studio provided unit testing
[TestClass]
public class PlayerServiceTest
{
// Should get all the players from database
[TestMethod]
public void GetAllPlayers()
{
// arrange - act
// TODO: Return all the players from the database
// assert
// TODO: Should return empty list
}
And the PlayerService class looks something like this
public class PlayerService
{
private PlayerRepository _playerRepository = new PlayerRepository();
public List<Player> GetAllPlayers()
{
var players = _playerRepository.GetAllPlayers();
return players;
}
PlayerRepository
public class PlayerRepository
{
public List<Player> GetAllPlayers()
{
using (var context = new PlayerContext())
{
var players = context.Players.ToList();
return players;
}
}
Generally my questions are:
How to make the PlayerContext with another connection string which connects to in-memory database in case of unit test, and also how to provide it with the correct connection string when not running via unit-tests
How to change the location of the database, because it's using a default path in C:\Users.
I'm not looking for integration tests with the DAL's PlayerRepository, I just want to test the business layer and all I need is, when I run the tests that the PlayerService to uses the PlayerRepository which connects to in-memory database and that's it. Otherwise it should connect to the local db stored in the same folder as the main exe for the app
Help needed!
The missing piece is dependency injection / IoC. The principle here is to define your dependencies (Repository) with a contract interface that can be mocked out. Inject that dependency into the classes that depend on it. This way you can substitute out concrete implementations like databases, file handling, etc. with mock up objects that return a known state, throw an expected exception, etc. to test your business logic's handling of those scenarios.
public class PlayerService
{
private readonly IPlayerRepository _playerRepository = null;
public PlayerService(IPlayerRepository playerRepository)
{
_playerRepository = playerRepository ?? throw new ArgumentNullException("playerRepository");
}
public List<Player> GetAllPlayers()
{
var players = _playerRepository.GetAllPlayers();
return players;
}
}
Have a look at IoC containers such as Autofac, Unity, Ninject, etc. for examples of how a container can be st up to automatically identify and inject concrete class instances into your services when it constructs them.
When you go to write a unit test you create a mock of the IPlayerRepository class (see: Moq for example) and pass that to your service under test. I.e.:
[Test]
public void TestService()
{
var mockRepository = new Mock<IPlayerRepository>();
mockRepository.Setup(x => x.GetPlayers()).Returns(buildTestPlayerList());
var serviceUnderTest = new PlayerService(mockRepository.Object);
// continue with test...
}
At a worst case: if you want to forgo the container, this can work as well:
public class PlayerService
{
private IPlayerRepository _playerRepository = null;
public IPlayerRepository PlayerRepository
{
get { return _playerRepository ?? (_playerRepository = new PlayerRepository()); }
set { _playerRepository = value; }
}
// ...
}
... and then with the test...
[Test]
public void TestService()
{
var mockRepository = new Mock<IPlayerRepository>();
mockRepository.Setup(x => x.GetPlayers()).Returns(buildTestPlayerList());
var serviceUnderTest = new PlayerService { PlayerRepository = mockRepository.Object };
// continue with test...
}
This is a pattern I call "lazy property injection" where you can opt to send a dependency in, but by default it will simply create the default dependency. This can be a useful pattern when introducing dependency substitution & unit testing into legacy code that was relying heavily on newing up classes mid-code. It's lazy in the sense that the dependency is only "newed" the first time it is accessed. If you call a method in the service that doesn't need the dependency then there is no initialization of every dependency, only the ones that are used. I highly recommend reading up on IoC containers though since they help automate wiring up dependencies.

Implement data access layer best practices in .net Project MVC

I would like to improve my .NET project by adding another layer when accessing the database. This is my code:
namespace Company.Models
{
public static class AgencyBean
{
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
DataAccess dataAccess = new DataAccess();
bool exists = dataAccess.checkIfExists(Id);
if(exist)
{
dataAccess.delete(Id);
}
retur "ok";
}
}
}
I placed DataAccess class in a separate folder called "Helpers" and it contains most of my queries:
public class DataAccess
{
public bool checkIfExists(String Id)
{
try
{
SqlConnection cnn = new SqlConnection(dataConnection);
cnn.Open();
SqlCommand check_Id = new SqlCommand("SELECT COUNT(*) FROM TABLE_GUID WHERE ([USER_ID] = #Id)", cnn);
check_Id.Parameters.AddWithValue("#Id", Id);
int UserExist = (int)check_Id.ExecuteScalar();
if (UserExist > 0)
{
return true;
}
else
{
return false;
}
}
catch (SqlException ex)
{
Debug.WriteLine("SQL Exception " + ex);
DisplaySqlErrors(ex);
throw ex;
}
}
}
public class AgentBeanController : Controller
{
// GET: AgentBean
public ActionResult Index(string name)
{
return View();
}
[AllowAnonymous]
[WebMethod]
public string AgentURL() //here we create Agent URL and return it to the view
{
string var = Models.AgentBean.createGUID("TODO");
return var;
}
}
I'm accessing the database pretty much in very direct way. How would it be with a better technique, so this access can be more secure, like accessing thru a service layer?
I'm connecting to a existing sql database in some server and working with MVC architecture in my project.
So here is what I have done in the past.
First, that is your "models" namespace... models should never have database connectivity. Instead you have a seperate class, such as a controller, that hydrates some model.
Second, I've had a "service" class, which hooks up to a "repository" class. The repository class implements an interface to identify the exact "type" of database you're using.. but if that's not a part of your requirements you probably don't need to go that far.
Third, look up dependency injection (aka, DI). There are several frameworks out there. Personally I've used Autofac, but others exist as well to get the job done easier.
Fourth, on your your "controllers", "services" and "respository" classes, implement dependency injection, as well as any interfaces as needed to form a contract.
Fifth, I would use an actual controller namespace and not be working out of your models namespace to be pushing http calls band and forth.... Instead, create an action in your controller class, and instantiate an instance of your "agencyBean", hydrate it with data, and return that model out to your view.
Basically, in a scenario like this you're trying to keep each component doing what it is designated to do... breaking down responsibilities into smaller pieces and focusing on that. Your controller should just "fetch" your model and maybe do some transformations on it as needed or any other business-type logic.
Your service should handle the communication between your controller and your database layer.
Your data access layer (ie, in this case, some "repository" class...) would do all of those new data connections and/or setting up calls to stored procedures or queries.
Doing things this way has a lot of benefit. Some of the big ones are maintainability, readability, code re-use. Sure it makes your project a bit more complicated in terms of files sitting wherever... but that can be a good thing. It's so much better than slamming everything into one single class and have it do everything :)
But, just FYI, this is from an implementation I've done in the past... I'm sure there are better ways but this setup worked quite well for my team and I.
Here is a small example using some of your code you posted. I DID NOT check this for typos and it wouldn't compile, but should help give a general idea of what I'm talking about....
namespace Company.Models
{
public class AgencyBean
{
public AgencyName{get;set;}
public AgencyId{get;set;}
// other properties...
}
}
namespace Company.Controllers
{
public class MyController : Controller
{
private readonly IMyService myService;
public MyController(IMyService myService) // <-- this is your dependency injection here...
{
this.myService = myService;
}
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
var model = new AgencyBean();
model.AgencyId = 1;
model = myService.getAgency(agencyBean);
return model;
}
}
}
namespace Company.Services
{
public class MyService
{
private readonly IMyRepository myRepository;
public MyService(IMyRepository myRepository) // <-- this is your dependency injection here...
{
this.myRepository = myRepository;
}
public AgencyBean getAgency(AgencyBean model){
var dataTable = myRepository.getAgencyData(model.AgencyId);
// fill other properties of your model you have...
// ...
// ...
return model;
}
}
}
namespace Company.Repositories
{
public class MyRepository : IDatabaseCommon // <-- some interface you would use to ensure that all repo type objects get connection strings or run other necessary database-like setup methods...
{
private readonly String connectionString{get;set;}
public MyRepository()
{
this.connectionString = //get your connection string from web.config or somewhere else...;
}
public DataTable getAgencyData(int id){
var dataTable = new DataTable();
// perform data access and fill up a data table
return dataTable;
}
}
}

Constructor injection and initialization of dependencies being injected

I am writing a simple console application that takes care of connecting to the database, selecting a particular product from it (based on the provided criteria) and doing some processing with this product. I am storing command-line arguments to an instance of this class:
public class Arguments
{
public string ConnectionString { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
}
At some point, I need to fetch the product from the database. I am using the following repository for that:
public interface IProductRepository
{
Product GetById(int productId, string connectionString);
Product GetByName(string productName, string connectionString);
}
Then, I inject an implementation of the repository to the class that uses it, e.g:
public class ProductProcessor
{
private readonly IProductRepository productRepository;
public ProductProcessor(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
public void Process(Arguments arguments)
{
Product productToProcess;
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName, arguments.ConnectionString);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId, arguments.ConnectionString);
}
// ....
}
}
This is working, but what I don't like about the design is that every method of the IProductRepository has a connectionString argument. If there was no dependency injection involved, I would probably rewrite it like the following:
public void Process(Arguments arguments)
{
Product productToProcess;
ProductRepository productRepository = new ProductRepository(arguments.ConnectionString);
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId);
}
// ....
}
This enables me to have simpler and easier-to-use interface. Of course, now the ProductRepository does not have parameterless constructor and it is difficult to use with DI container. Ideally, I would like to have the best of both worlds, i.e. to initialize the ProductRepository with the connection string from constructor and remove the connection string from its methods. What is the best approach to achieve this?
Some approaches I've already considered:
Add a method Initialize(string connectionString) to the IProductRepository that would basically serve as a constructor. Obvious drawback is that I now need to check whether the Initialize has been called before doing anything in GetById or GetByName methods.
Do not use constructor injection and use Service Locator pattern instead to instantiate ProductRepository. I don't like Service Locator much, but this is probably only possible solution.
Is there any better alternative?
EDIT: From the answers I see that I should have posted a bit more context. I am using Ninject as my DI container. In Main method in my Program.cs, I register all dependencies to the container and instantiate the class that serves as an entry-point to the application:
public static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<IArgumentsParser>().To<IArgumentsParser>();
kernel.Bind<IProductProcessor>().To<ProductProcessor>();
kernel.Bind<IProductRepository>().To<ProductRepository>();
MainClass mainClass = kernel.Get<MainClass>();
mainClass.Start(args);
}
The MainClass looks like the following:
public class MainClass
{
private readonly IArgumentsParser argumentsParser;
private readonly IProductProcessor productProcessor;
public MainClass(IArgumentsParser parser, IProductProcessor processor)
{
argumentsParser = parser;
productProcessor = processor;
}
public void Start(string[] args)
{
Arguments parsedArguments = argumentsParser.Parse(args);
productProcessor.Process(parsedArguments );
}
}
This enables me to have a dependency to Ninject and creation of the whole graph in one place only (the Main method) and the rest of the application knows nothing about DI and containers.
I'd like to keep it that way, if possible.
I agree that the current interface design is a leaky abstraction, so let's define it like this instead:
public interface IProductRepository
{
Product GetById(int productId);
Product GetByName(string productName);
}
What you need then is an Abstract Factory that can create an instance of IProductRepository for you.
So ProductProcessor could look like this:
public class ProductProcessor
{
private readonly IProductRepositoryFactory productRepositoryFactory;
public ProductProcessor(IProductRepositoryFactory productRepositoryFactory)
{
this.productRepositoryFactory = productRepositoryFactory;
}
public void Process(Arguments arguments)
{
Product productToProcess;
var productRepository =
this.productRepositoryFactory.Create(arguments.ConnectionString);
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId);
}
// ....
}
}
I'm not sure why you need to model the command line arguments at all? You should minimize the dependencies on each of your types. This means the product repository should take the connection string as a constructor parameter (because it's a required dependency), and your product processor should take the product id and product name (if this is the best way you feel to do dynamic queries).
Therefore, assuming your product repository is a singleton, you would new it up at the point you do your registrations (passing in the connection string), and then register this in your IoC container against your abstraction.
You could then new up a product processor (passing in the product id and product name) and register this as singleton against an abstraction. You can then use constructor injection to pass the product processor into any type that requires it.
Of course, now the ProductRepository does not have parameterless
constructor and it is difficult to use with DI container.
On the contrary, most DI containers allow you to work with parameterized constructors. In fact, when doing Dependency Injection, constructor injection is the advised approach, which means you will have non-default constructors. Having a constructor that takes in a primitive type (such as a string dependency), might mean that some containers won't be able to do auto-wiring for you. Auto-wiring means that the container will figure out what to inject. However, with your product repository, this problem can easily be solved by supplying a initialized instance to the container (if you need a single instance), or supplying a factory delegate (if you need a new instance on each call). It depends on which framework you use, but it might look like this:
container.RegisterSingle(new SqlProductFactory("constring"));
When you supply the connection string in the SqlProductFactory's constructor, you won't have to pass it in (using method injection) to the factory, and you don't need this connection string in your Arguments class.
What you can do is to decouple object creation from object look up. The DI container will look up for instance you have registered at the start up. At that point you can pass in the connection string as a constructor argument to your repository.
This is how the product code would look like;
public class ProductRepository : IProductRepority
{
private readonly string connString;
public ProductRepository(string conn)
{
connString = conn;
}
}
You can wrap connection string with another type too if needed. The important point is, DI will inject instances required based on the binding done at the type graph during start up. Based on the registration you can simply extract connection string from the args and pass it along the ProductRepository registration.
EDIT
See the following answer for how to solve you stated problem.
However, I would really recommend using an existing IOC package, such as Windsor or nHibernate. See https://stackoverflow.com/questions/2515124/whats-the-simplest-ioc-container-for-c for some details.
END EDIT
Why not add ConnectionString as a Property to IProductRepository.
So the interface is:
public interface IProductRepository
{
string ConnectionString { get; set; }
Product GetById(int productId);
Product GetByName(string productName);
}
And the processor becomes:
public void Process(Arguments arguments)
{
Product productToProcess;
var productRepository = new ProductRepository
{ ConnectionString = arguments.ConnectionString};
if (!string.IsNullOrEmpty(arguments.ProductName))
productToProcess = productRepository.GetByName(arguments.ProductName);
else
productToProcess = productRepository.GetById(arguments.ProductId);
// ....
}

Writing a testable "import data from database" class

I am tasked with pulling all the rows from a 3rd party vendor's SQLite data table, creating business objects from those records, and sending the new business objects off to another class.
Pseudo-code:
var databasePath = "%user profile%\application data\some3rdPartyVendor\vendor.sqlite"
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
I've got all that working.
My question is: How can I write this class so it's unit testable?
Should I:
use the repository pattern to mock out the data access
actually provide a dummy SQLite database in the unit test
Or any better ideas? I'm using C#, but this question seems rather language-agnostic.
You could inject a test-only Sqlite database quite easily, refactoring the code to look like below. But how are you asserting the results? The business objects are passed to someOtherClass. If you inject an ISomeOtherClass, that class's actions need to be visible too. It seems like a bit of pain.
public class KillerApp
{
private String databasePath;
private ISomeOtherClass someOtherClass;
public KillerApp(String databasePath, ISomeOtherClass someOtherClass)
{
this.databasePath = databasePath;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(DatabasePath, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
Using an IRepository would remove some of the code from this class, allowing you to mock the IRepository implementation, or fake one just for test.
public class KillerApp
{
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass;
public KillerApp(IRepository<BusinessObject> repository, ISomeOtherClass someOtherClass)
{
this.repository = repository;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = repository.FindAll();
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
repository = new BusinessObjectRepository(DatabasePath);
app = new KillerApp(repository, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
But this still feels quite cumbersome. There are two reasons, 1) the Repository pattern has been getting some bad press lately from Ayende, who knows a thing or two about Repository. And 2) what are you doing writing your own data access!? Use NHibernate and ActiveRecord!
[ActiveRecord] /* You define your database schema on the object using attributes */
public BusinessObject
{
[PrimaryKey]
public Int32 Id { get; set; }
[Property]
public String Data { get; set; }
/* more properties */
}
public class KillerApp
{
private ISomeOtherClass someOtherClass;
public KillerApp(ISomeOtherClass someOtherClass)
{
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = BusinessObject.FindAll() /* built-in ActiveRecord call! */
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing : ActiveRecordTest /* setup active record for testing */
{
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
The result is a much smaller class and a business object and data-layer that you can change more easily. And you don't even have to mock the database calls, you can configure and initialize ActiveRecord to use a test database (in-memory, even).
Well, the only thing that would really need to be tested here is TransformIntoBizObjs, I would think, since the connection code should have been written/tested elsewhere. Simply passing things that might show up to Transform and seeing if the right thing pops out would be what you need to do.
Remember to test all usecases of Transform, even potentially weird items that probably shouldn't end up in the function call, but might. Never know what people have been shoving in their databases.
Inversion of Control (IoC) and Dependency Injection (DI) will go a long way towards making your code more testable. There are a lot of frameworks out there that can assist you with this, but for your purposes you don't necessarily need to go to all that effort.
Start with extracting an interface that might look something like this:
Interface ISqlLiteConnection
{
public IList<GizmoRecord> Query(...);
}
Once you've done that, you should refactor the OpenSqlLiteConnection() method to return an instance of ISqlLiteConnection, rather than the concrete implementation. To test, just create a class that implements your interface, which mocks up the actual DB queries and connections with determinate results.
Databases are complicates, you need to test your query code and you need to test it against a real sqlite instance - otherwise you can't be sure you didn't hit some rare sqlite quirk or bug.
And since the only way to test your query is to run it on a real sqlite file, and it's really easy to include such a file with your test there's no point to adding another layer just to make it "more" testable or to have "pure" unit tests.
Just make sure to add all the strange edge cases you can think of to your sample file.

Categories