没有数据库的unit testing:Linq to SQL

我有一个使用LINQ to SQL实现的存储库。 虽然我没有数据库,但我需要进行unit testing。 如何为FreezeAllAccountsForUser方法编写UT? 你能用手动模拟来展示一个例子吗?

注意:域对象中使用了inheritance映射

注意:unit testing将使用Visual Studio Team Test完成

来自@StuperUser的评论。 unit testing涉及将代码与其交互的其他对象完全隔离。 这意味着如果代码失败,您可以确定失败是与测试中的代码有关。 要做到这一点,你必须伪造这些对象。

public void FreezeAllAccountsForUser(int userId) { List bankAccountDTOList = new List(); IEnumerable accounts = AccountRepository.GetAllAccountsForUser(userId); foreach (DBML_Project.BankAccount acc in accounts) { string typeResult = Convert.ToString(acc.GetType()); string baseValue = Convert.ToString(typeof(DBML_Project.BankAccount)); if (String.Equals(typeResult, baseValue)) { throw new Exception("Not correct derived type"); } acc.Freeze(); DTOLayer.BankAccountDTOForStatus presentAccount = new DTOLayer.BankAccountDTOForStatus(); presentAccount.BankAccountID = acc.BankAccountID; presentAccount.Status = acc.Status; bankAccountDTOList.Add(presentAccount); } IEnumerable el = bankAccountDTOList.Select(x => new System.Xml.Linq.XElement("BankAccountDTOForStatus", new System.Xml.Linq.XElement("BankAccountID", x.BankAccountID), new System.Xml.Linq.XElement("Status", x.Status) )); System.Xml.Linq.XElement root = new System.Xml.Linq.XElement("root", el); //AccountRepository.UpdateBankAccountUsingParseXML_SP(root); AccountRepository.Update(); } 

存储库层

 namespace RepositoryLayer { public interface ILijosBankRepository { System.Data.Linq.DataContext Context { get; set; } List GetAllAccountsForUser(int userID); void Update(); } public class LijosSimpleBankRepository : ILijosBankRepository { public System.Data.Linq.DataContext Context { get; set; } public List GetAllAccountsForUser(int userID) { IQueryable queryResultEntities = Context.GetTable().Where(p => p.AccountOwnerID == userID); return queryResultEntities.ToList(); } public virtual void Update() { //Context.SubmitChanges(); } } } 

域类

 namespace DBML_Project { public partial class BankAccount { //Define the domain behaviors public virtual void Freeze() { //Do nothing } } public class FixedBankAccount : BankAccount { public override void Freeze() { this.Status = "FrozenFA"; } } public class SavingsBankAccount : BankAccount { public override void Freeze() { this.Status = "FrozenSB"; } } } 

LINQ to SQL自动生成的类

 [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")] [InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)] [InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))] public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged 

存储库的职责是持久保存域对象并根据请求获取它们。 即它的工作是获取一个对象并将其反序列化/序列化为某种forms的持久存储。

因此,对于存储库的测试必须针对真实存储进行测试,在这种情况下是数据库。 即这些是集成测试 – 您的类与外部数据库集成的测试。

一旦你有了这个钉子,客户端/应用程序的其余部分就不必对真正的数据库起作用了。 他们可以模拟存储库并进行快速unit testing。 您可以假设GetAccount在集成测试通过后仍然有效。

更多细节:通过传递Repository对象作为ctor或方法arg,您打开了传递假或模拟的大门。 因此,现在服务测试可以在没有真实存储库的情况下运行>>没有DB-access >>快速测试。

 public void FreezeAllAccountsForUser(int userId, ILijosBankRepository accountRepository) { // your code as before } test () { var mockRepository = new Mock(); var service = // create object containing FreezeAllAccounts... service.FreezeAllAccounts(SOME_USER_ID, mockRepository); mock.Verify(r => r.GetAllAccountsForUser(SOME_USER_ID); mock.Verify(r => r.Update()); } 

简单地说,你不能。 存储库实现的唯一目的是与数据库通信。 因此数据库技术很重要,您应该执行集成测试。

unit testing此代码是不可能的,因为LINQ to Objects是LINQ to SQL的超集。 您可能有一个绿色unit testing,并且在使用真实数据库时仍然会获得运行时exception,因为您在存储库中使用了无法转换为SQL的LINQfunction。

您可以在datacontext中使用IDbSet接口并为datacontext类提取接口。 对接口进行编程是创建单元可测试代码的关键。

您希望为这些linq查询创建unit testing的原因是对逻辑查询进行unit testing。 集成测试受到各种漏报的影响。 数据库不处于正确状态,其他查询同时运行,其他集成测试等等。很难将数据库隔离得足够好以进行可靠的集成测试。 这就是集成测试经常被忽略的原因。 如果我必须选择一个,我想要unit testing……