2016-03-12 2 views
0

У нас есть методы, которые возвращают соответствующую запись базы данных или если не существует соответствия, создает запись и возвращает ее. Использование Entity Framework.Как проверить метод, который зависит от содержимого базы данных?

public Transaction FindOrCreateTransactionByID(string id, DBContext db) 
{ 
    Transaction t = db.Transactions.SingleOrDefault(f => f.TransactionID == id); 
    if(t == null) 
    { 
     t = new Transaction { TransactionID = id }; 
     db.Transactions.Add(t); 
     db.SaveChanges(); 
    } 
    return t; 
} 

Существует больше методов, чем указано выше, но это должно иллюстрировать сценарий.

Должны ли мы попытаться высмеять DBContext? Пройдите в DbSet[Transactions] и издевайтесь над этим? Разбить метод на Find() и Create() вместо этого?

+0

Вы прочитали статью [this] (https://msdn.microsoft.com/en-us/library/dn314429.aspx?f=255&MSPPError=-2147217396)? Какую версию EF вы используете? –

ответ

0

Я попытался скопировать ваш код локально, чтобы написать простой тест для метода, упомянутого в вашем вопросе. Вот что я получил:

public class Transaction 
{ 
    public string TransactionID { get; set; } 
} 

public class DBContext : DbContext 
{ 
    public virtual DbSet<Transaction> Transactions { get; set; } 
} 

public class TransactionService 
{ 
    public Transaction FindOrCreateTransactionByID(string id, DBContext db) 
    { 
     Transaction t = db.Transactions.SingleOrDefault(f => f.TransactionID == id); 
     if (t == null) 
     { 
      t = new Transaction { TransactionID = id }; 
      db.Transactions.Add(t); 
      db.SaveChanges(); 
     } 
     return t; 
    } 
} 

[TestFixture] 
public class TransactionServiceTests 
{ 
    [Test] 
    public void When_transaction_not_found_new_transaction_created() 
    { 
     const string id = "_id_"; 

     var mockSet = new Mock<DbSet<Transaction>>(); 

     // setup data 
     IQueryable<Transaction> data = new List<Transaction>().AsQueryable(); 
     mockSet.As<IQueryable<Transaction>>().Setup(m => m.Provider).Returns(data.Provider); 
     mockSet.As<IQueryable<Transaction>>().Setup(m => m.Expression).Returns(data.Expression); 
     mockSet.As<IQueryable<Transaction>>().Setup(m => m.ElementType).Returns(data.ElementType); 
     mockSet.As<IQueryable<Transaction>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator); 

     var mockContext = new Mock<DBContext>(); 
     mockContext.SetupGet(x => x.Transactions).Returns(mockSet.Object); 

     var service = new TransactionService(); 
     service.FindOrCreateTransactionByID(id, mockContext.Object); 

     mockSet.Verify(
      set => set.Add(It.Is<Transaction>(t => t.TransactionID == id)), 
      Times.Once); 
     mockContext.Verify(context => context.SaveChanges(), Times.Once); 
    } 
} 

Тест был написан с использованием NUnit, но вы можете заменить его с любимой модульного тестирования рамки без каких-либо проблем. Самая сложная часть заключалась в том, чтобы выяснить, как издеваться над транзакциями DbSet, поэтому вызов SingleOrDefault будет работать, не бросая ArgumentNullException. Как вы можете видеть, это было достигнуто путем насмешливого поведения IQueryable для транзакций. Все остальное было действительно куском пирога.

0

Я сделал некоторые тестовые примеры для вас через Typemock Isolator, что делает его легче издеваться DbContext:

public class Transaction 
{ 
    public string TransactionID { get; set; } 
    public string TransactionName { get; set; } 
} 

public class DBContext : DbContext 
{ 
    public DbSet<Transaction> Transactions { get; set; } 
} 

public class TransactionService 
{ 
    public Transaction FindOrCreateTransactionByID(string id, DBContext db) 
    { 
     Transaction t = db.Transactions.SingleOrDefault(f => f.TransactionID == id); 
     if (t == null) 
     { 
      t = new Transaction { TransactionID = id }; 
      db.Transactions.Add(t); 
      db.SaveChanges(); 
     } 
     return t; 
    } 
} 

[TestClass] 
public class UnitTest 
{ 
    [TestMethod, Isolated] 
    public void TestTransactionExist() 
    { 
     var service = new TransactionService();   
     string id = "id"; 
     string name = "name"; 

     var fakeDb = new DBContext(); 
     var fakeDbSet = Isolate.Fake.Instance<DbSet<Transaction>>(); 

     List<Transaction> data = new List<Transaction>() 
     { 
      new Transaction { TransactionID = id, TransactionName = name } 
     }; 

     Isolate.WhenCalled(() => fakeDb.Transactions).WillReturnCollectionValuesOf(data.AsQueryable()); 

     Transaction res = service.FindOrCreateTransactionByID(id, fakeDb); 

     Assert.AreEqual(name, res.TransactionName); 
    } 

    [TestMethod, Isolated] 
    public void TestNewTransaction() 
    { 
     var service = new TransactionService(); 
     string id = "id"; 

     var fakeDb = new DBContext(); 
     var fakeDbSet = Isolate.Fake.Instance<DbSet<Transaction>>(); 

     List<Transaction> data = new List<Transaction>(); 

     Isolate.WhenCalled(() => fakeDb.Transactions).WillReturnCollectionValuesOf(data.AsQueryable()); 
     Isolate.WhenCalled(() => fakeDb.Transactions.Add(null)).DoInstead(
     context => 
     { 
      data.Add(context.Parameters[0] as Transaction); 
      return context.Parameters[0] as Transaction; 
     }); 

     Transaction res = service.FindOrCreateTransactionByID(id, fakeDb); 

     Assert.AreEqual(id, res.TransactionID); 
    } 
} 

Надеется, что это помогает!

Смежные вопросы