Hi I am attempting to write a unit test for a class CommandBusiness:
public class CommandBusiness
{
IRepository<Command> _repository;
public CommandBusiness(IRepository<Command> repository)
{
_repository = repository;
}
public List<Command> GetCommandsFromProjectId(int id)
{
return _repository.SearchFor(command => command.ProjectId == id);
}
public List<Command> GetAll()
{
return _repository.GetAll();
}
public void Delete(int id)
{
Entities.Command command = _repository.GetById(id);
_repository.Delete(command);
}
}
public interface IRepository<T> where T : new()
{
void Delete(T entity);
List<T> SearchFor(Expression<Func<T, bool>> predicate);
List<T> GetAll();
T GetById(int id);
}
public class OrmLiteRepository<T> : IRepository<T> where T : new()
{
public IDbConnectionFactory DbFactory { get; private set; }
string ConnectionString = "";
public OrmLiteRepository()
{
DbFactory = null; // OrmLiteConnectionFactory(ConfigurationManager.AppSettings["ConnectionString"].ToString(), SqlServerDialect.Provider);
}
public List<T> SearchFor(Expression<Func<T, bool>> predicate)
{
using (IDbConnection db = DbFactory.OpenDbConnection())
{
return db.Select(predicate);
}
}
public List <T> GetAll()
{
using (IDbConnection db = DbFactory.OpenDbConnection())
{
return db.Select<T>();
}
}
public void Delete(T entity)
{
using (IDbConnection db = DbFactory.OpenDbConnection())
{
db.Delete<T>(entity);
}
}
public T GetById(int Id)
{
using (IDbConnection db = DbFactory.OpenDbConnection())
{
return db.GetById<T>(Id);
}
}
}
public class Command
{
public int Id { get; set; }
public string CommandText
{
get;
set;
}
public bool AppendToNextLine
{
get;
set;
}
public int ProjectId
{
get;
set;
}
public int SortOrder
{
get;
set;
}
}
public class Testing
{
[TestMethod]
public void TestMethod()
{
List<Command> commandsx = new List<Command>
{
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 1, ProjectId = 1 , SortOrder = 1},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 2, ProjectId = 1 , SortOrder = 2},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 3, ProjectId = 2 , SortOrder = 3},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 4, ProjectId = 2 , SortOrder = 4},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 5, ProjectId = 3 , SortOrder = 5},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 6, ProjectId = 3 , SortOrder = 6},
new Command { AppendToNextLine = false, CommandText = "SomeText", Id = 7, ProjectId = 3 , SortOrder = 7}
};
Mock<IRepository<Command>> mockProductRepository = new Mock<IRepository<Command>>();
mockProductRepository.Setup(mPR => mPR.GetAll()).Returns(commandsx);
var comBusiness = new CommandBusiness(mockProductRepository.Object);
var comsoriginal = comBusiness.GetAll();
comBusiness.Delete(3);
comsoriginal = comBusiness.GetAll();
}
}
When I attempt to run the above code I get comsoriginal out as holding 7 items, next I execute the delete command and then requery the comBusiness.GetAll and again I get a count of 7, I would have expected a count of 6. Any thoughts????
you code for CommandBusiness.GetAll()
does this:
public List<Command> GetAll()
{
return _repository.GetAll();
}
you create a mock for your repository which does return a fixed list:
Mock<IRepository<Command>> mockProductRepository = new Mock<IRepository<Command>>();
mockProductRepository.Setup(mPR => mPR.GetAll()).Returns(commandsx);
regardless of how many times you call CommandBusiness.GetAll()
you will always get back the fixed list. that is what mocks do.
In actuality what you want to test for your CommandBusiness
is not that the number of entities returned is correct, but only that it interacts with its dependecies (in this case the IRepository
) correctly. The CommandBusiness
unit does not have the responsibility for deleting the Commands, it delegates this command to the IRepository
. Assuming that the repository does its job of deleting correctly the only functionality of this class is to call the correct method on the IRepository
. So for a true unit test you should create a mock IRepository
and set an expectation that Delete with the value 3 will be called, then call Delete with a value 3 on your CommandBusiness
and verify that the expected call does indeed happen.
IMHO these tests do not provide significant value as the are really testing the implementation of CommandBusiness
and not the behavior. These tests are brittle and will need to change every time the implementation changes.
I would prefer a test which actually interacts with the repository (like the one you have written) (even if that is slower) as this tests the behaviour, regardless of how it is implemented.
You could create a test which tests the combination of your CommandBusiness
and IRepository
by creating a TestRepository
class which just wraps a simple collection. then you could use your existing test, but pass your TestRepository
in instead of your current mock IRepository
and then your test should pass, as the CommandBusiness
will have an actual repository which will be being affected by the Delete
method as well as the GetAll
method.
Alternatively don't have a mock or a TestRepository, just use the real OrmLightRepository and spin up a new DB for the test. This will validate that everything actually works in the real situation.
The best of all worlds would be to make the repository configurable in the tests. Most of the time use a standard in memory collection for your respository. This will mean your tests are fast. But you can't be sure that you didn't use some linq command which won't be supported by the actual DB, so on the CI server use config to switch the tests to a real DB and verify that things will actually work in real life.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments