繁体   English   中英

没有数据库的单元测试:Linq to SQL

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM