问题描述
我有一个使用 LINQ to SQL 实现的存储库.虽然我没有数据库,但我需要进行单元测试.如何为 FreezeAllAccountsForUser 方法编写 UT?你能展示一个使用手动模拟的例子吗?
I have a repository implemented using LINQ to SQL. I need to do Unit Testing though I don't have a database. How can I write the UT for FreezeAllAccountsForUser method? Can you please show an example using manually mocking?
注意:域对象中使用了继承映射
Note: There is inheritance mapping used in domain objects
注意:单元测试将使用 Visual Studio Team Test 完成
Note: Unit Testing is to be done using Visual Studio Team Test
来自@StuperUser 的评论.单元测试涉及将代码与其交互的其他对象完全隔离.这意味着如果代码失败,您可以确定失败与被测代码有关.为此,您必须伪造这些对象.
Comment from @StuperUser. Unit testing involves completely isolating code from the other objects it interacts with. This means that if the code fails, you can be sure that the failure is to do with the code under test. To do this you have to fake these objects.
代码
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 自动生成的类
Auto generated Class by 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
推荐答案
Repository 的职责是持久化域对象并根据请求获取它们.即它的工作是获取一个对象并将其反序列化/序列化为某种形式的持久存储.
The Repository responsibility is to persist domain objects and fetch them on request. i.e. it's job is to take an object and deserialize/serialize it to from some form of durable storage.
因此对存储库的测试必须针对实际存储进行测试,在这种情况下是数据库.即这些是集成测试 - 测试您的类与外部数据库集成.
So tests for the repository have to test against the real storage in this case a DB. i.e. these are integration tests - tests that your class integrates with the external DB.
一旦你确定了这一点,客户端/应用程序的其余部分就不必针对真正的数据库工作了.他们可以模拟存储库并进行快速的单元测试.您可以假设自集成测试通过以来 GetAccount 工作正常.
Once you have this nailed, the rest of the client/app doesn't have to work against the real DB. They can mock the repository and have fast unit tests. You can assume that GetAccount works since the integration tests pass.
更多详情:通过将 Repository 对象作为 ctor 或方法 arg 传入,您为传入伪造或模拟打开了大门.因此,现在服务测试可以在没有真正存储库的情况下运行 >> 没有数据库访问 >> 快速测试.
More details: By passing in the Repository object as a ctor or method arg, you open the doors for passing in a fake or a mock. Thus now the service tests can run without a real repository >> there is no DB-access >> fast tests.
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());
}
这篇关于没有数据库的单元测试:Linq to SQL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!