[英]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.