[英]Unit Testing without Database: Linq to SQL
我有一个使用LINQ to SQL实现的存储库。 我没有数据库,但我需要进行单元测试。 如何为FreezeAllAccountsForUser方法编写UT? 您能否显示一个使用手动模拟的示例?
注意:域对象中使用了继承映射
注意:单元测试将使用Visual Studio Team Test完成
@StuperUser的评论。 单元测试涉及将代码与与其交互的其他对象完全隔离。 这意味着,如果代码失败,则可以确定失败与被测试代码有关。 为此,您必须伪造这些对象。
码
public void FreezeAllAccountsForUser(int userId)
{
List<DTOLayer.BankAccountDTOForStatus> bankAccountDTOList = new List<DTOLayer.BankAccountDTOForStatus>();
IEnumerable<DBML_Project.BankAccount> 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<System.Xml.Linq.XElement> 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<DBML_Project.BankAccount> GetAllAccountsForUser(int userID);
void Update();
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
public System.Data.Linq.DataContext Context
{
get;
set;
}
public List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID)
{
IQueryable<DBML_Project.BankAccount> queryResultEntities = Context.GetTable<DBML_Project.BankAccount>().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
简单地说,你做不到。 存储库实现的唯一目的是与数据库对话。 因此,数据库技术确实很重要,您应该执行集成测试。
由于LINQ to Objects是LINQ to SQL的超集,因此无法对该代码进行单元测试。 您可能有一个绿色的单元测试,并且在使用实际数据库时仍然会遇到运行时异常,因为您在存储库中使用了LINQ的功能,该功能无法转换为SQL。
存储库的责任是保留域对象,并根据请求获取它们。 也就是说,它的工作是从某个持久存储中获取一个对象并将其反序列化/序列化为对象。
因此,对于存储库的测试必须针对实际存储(在这种情况下为DB)进行测试。 也就是说,这些是集成测试-您的类与外部DB集成的测试。
一旦确定了这一点,其余的客户端/应用程序就不必针对实际的数据库工作。 他们可以模拟存储库并进行快速的单元测试。 您可以假定GetAccount在集成测试通过后就可以使用了。
更多详细信息:通过将Repository对象作为ctor或方法arg传递,您可以打开传递伪造或模拟的大门。 因此,现在服务测试可以在没有真实存储库的情况下运行>>没有DB访问>>快速测试。
public void FreezeAllAccountsForUser(int userId, ILijosBankRepository accountRepository)
{
// your code as before
}
test ()
{ var mockRepository = new Mock<ILijosBankRepository>();
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());
}
您可以通过在数据上下文中使用IDbSet接口并为数据上下文类提取接口来实现。 对接口进行编程是创建单元可测试代码的关键。
您要为这些linq查询创建单元测试的原因是要对逻辑查询进行单元测试。 集成测试易受各种假阴性的影响。 db处于不正确的状态,其他查询同时运行,其他集成测试,等等。很难很好地隔离数据库以进行可靠的集成测试。 这就是为什么集成测试经常被忽略的原因。 如果我必须选一个,我要单元测试...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.