我是否以正确的方式测试我的存储库?

时间:2014-06-26 16:15:17

标签: c# unit-testing tdd

我有一个像这样的通用存储库:

public interface IRepository<TEntity> where TEntity :class
{
    IEnumerable<TEntity> SearchFor(Expression<Func<TEntity, bool>> filter);
    TEntity GetById(int id);
    void Insert(TEntity entity);
    void Delete(TEntity entity);
    void Update(TEntity entity);
}
public class GenericRepository<TEntity> : IRepository<TEntity>  where TEntity: class
{
    private DbSet<TEntity> _dbSet; // put the entity specified in place of TEntity in d DbSet so i can query the entity e.g School Entity
    private NaijaSchoolsContext _naijaSchoolsContext;

    public GenericRepository(NaijaSchoolsContext context)
    {
        _naijaSchoolsContext = context;
        _dbSet = _naijaSchoolsContext.Set<TEntity>(); //return the entity specified in the TEntity and put it in DbSet
    }

    public IEnumerable<TEntity> SearchFor(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter)
    {
        return _dbSet.Where(filter);
    }

    public TEntity GetById(int id)
    {
        return _dbSet.Find(id);
    }

    public void Insert(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    public void Delete(TEntity entity)
    {
        _dbSet.Remove(entity);
    }

    public void Update(TEntity entity)
    {
        _dbSet.AddOrUpdate(entity);
    }
}

我也有这样的UoW:

public interface IUnitofWork : IDisposable
{
    void Save();
}

public class UnitofWork : IUnitofWork
{
    NaijaSchoolsContext naijaSchoolsContext = new NaijaSchoolsContext();
    private GenericRepository<School> schoolRepository;
    private bool isDisposed = false;

    public GenericRepository<School> SchoolRepository
    {
        get
        {
            if (schoolRepository == null)
            {
                schoolRepository = new GenericRepository<School>(naijaSchoolsContext);
            }
            return schoolRepository;
        }
    }

    public void Save()
    {
        naijaSchoolsContext.SaveChanges();
    }

    public void Dispose(bool disposing)
    {
        if (!isDisposed)
        {
            if (disposing)
            {
                naijaSchoolsContext.Dispose();
            }
        }
    }

    public void Dispose()
    {
       Dispose(true);
       GC.SuppressFinalize(this);
    }
}

我的测试类看起来像这样:

 [TestFixture]
public class when_working_with_school_repository
{

}

public class and_saving_a_school : when_working_with_school_repository
{
    private School _returnedSchool;
    private School _school;
    private Mock<IRepository<School>> _repository;
    private Exception _result;


    [SetUp]
    private void SetUp()
    {
        _repository = new Mock<IRepository<School>>();
        _school = new School();
    }

    [Test]
    public void then_a_valid_school_should_be_saved()
    {
        _repository.Setup(s => s.Insert(_school));
        //_returnedSchool = _schoolRepository.Save(_school);
    }

    [Test]
    public void should_throw_an_exception_when_no_school_is_saved()
    {
        try
        {
            _repository.Setup(s => s.Insert(null));
        }
        catch (Exception exception)
        {
            _result = exception;
        }
    }

    [Test]
    public void should_notify_user_if_school_name_already_exists()
    {
        //bool exists = _schoolRepository.IsExist(_school.Name);
    }
}

我的测试通过,但我担心的是

  1. 我不应该嘲笑UnitOfWork类。当我尝试模拟它时,我无法进入StudentRepository类。在没有测试的情况下使用代码时,我必须实例化UoW来执行我的操作,这就是为什么我问我是否应该模拟我的UoW。如果我要模拟它我怎么能这样做?
  2. 如果我的测试是正确的,或者我需要采取其他行动,请帮助我。

2 个答案:

答案 0 :(得分:0)

我认为你最好嘲笑IRepository。但是,你的测试将通过,因为你没有断言任何事情。

我认为您需要设置您的模拟以获得所需的结果。这是一个修改过的例子:

[Test]
public void then_a_valid_school_should_be_saved()
{
    var _school = new School { .... };
    var expected = _school.Id;
    _repository.Setup(s => s.Insert(_school));
    _repository.Setup(s => s.GetById(_school.Id)).Returns(_school);;

    _repository.Insert(_school);
    var actual = _repository.GetById(_school.Id);

    Assert.Equal(expected, actual);
}

应该这样做。要使测试失败,请尝试为预期结果添加不同的Id并验证其是否有效。您可以使用它来改进您的其他测试。

答案 1 :(得分:0)

不,你不是。您正在测试 mock

_repository = new Mock<IRepository<School>>();

您想要测试您的代码,而不是其他人。您的通用存储库只是将调用委托给_dbSet。这就是你想要测试的 - 调用是委托的(这是一种包装功能)。

怎么做?您需要对DbSet<T>进行抽象,这是您在测试中模拟的对象。您的所有测试看起来都相似:

var dbSetMock = new Mock<DbSet<School>>();
var context = new Mock<Context>();
var repository = new GenericRepository<School>(dbSetMock, context);

repository.FindBy(arg);

dbSetMock.Verify(d => d.FindBy(arg));

这需要对DbSet和您的自定义上下文进行抽象,以使其正常工作。