2

我有一个使用 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
4

3 回答 3

5

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

对这段代码进行单元测试是不可能的,因为 LINQ to Objects 是 LINQ to SQL 的超集。您可能有一个绿色单元测试,但在使用真实数据库时仍然会出现运行时异常,因为您在存储库中使用了无法转换为 SQL 的 LINQ 功能。

于 2012-07-05T17:09:02.673 回答
2

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

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

一旦确定了这一点,客户端/应用程序的其余部分就不必针对真实的数据库工作。他们可以模拟存储库并进行快速的单元测试。您可以假设 GetAccount 在集成测试通过后可以正常工作。

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

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());
}
于 2012-07-06T06:04:13.593 回答
0

您可以通过在数据上下文中使用 IDbSet 接口并为数据上下文类提取接口。面向接口的编程是创建可单元测试代码的关键。

您希望为这些 linq 查询创建单元测试的原因是对逻辑查询进行单元测试。集成测试会受到各种假阴性的影响。数据库未处于正确状态,同时运行其他查询,其他集成测试等。很难将数据库隔离到足以进行可靠集成测试的程度。这就是为什么集成测试经常被忽略的原因。如果我必须选择一个,我想要单元测试......

于 2017-01-11T00:36:45.793 回答