Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何有效地对这个复杂的查询进行单元测试?_C#_Unit Testing_Nhibernate_Castle Windsor_Moq - Fatal编程技术网

C# 如何有效地对这个复杂的查询进行单元测试?

C# 如何有效地对这个复杂的查询进行单元测试?,c#,unit-testing,nhibernate,castle-windsor,moq,C#,Unit Testing,Nhibernate,Castle Windsor,Moq,我处理一个大型应用程序。代码库主要分为不同的任务,每个任务通过DI接收其依赖项(通常是存储库),例如这个简化的理论类: public class EmailTasks { public EmailTasks( IUserRepository userRepository ) { UserRepository = userRepository; } private readonly IUserRepository UserRepository;

我处理一个大型应用程序。代码库主要分为不同的任务,每个任务通过DI接收其依赖项(通常是存储库),例如这个简化的理论类:

public class EmailTasks
{
    public EmailTasks( IUserRepository userRepository )
    {
        UserRepository = userRepository;
    }

    private readonly IUserRepository UserRepository;

    public void SendNoticeEmail( DateTime minDate, DateTime maxDate, etc... )
    {
        var users = GetUsersWithNotices( minDate, maxDate, etc... );

        // send email to each user
    }

    private IEnumerable<User> GetUsersWithNotices( DateTime minDate, DateTime maxDate, etc... )
    {
        return UserRepository.FindAll( u => u.Active && !u.Whatever
                                            && u.JoinDate > minDate && u.JoinDate < maxDate
                                            && u.Notices.Any( n => n.Active && !n.Something
                                                                   && Whatever
                                                                   && etc... ) );
    }
}
显然,这并不能测试用户是否符合标准。我针对模拟结果编写的任何测试
UserRepository.FindAll
都只会验证我模拟的内容

那么,我怎样才能有效地对这个复杂的查询进行单元测试呢

编辑

我试图从查询中分离业务逻辑:

public class EmailTasks
{
    public EmailTasks( IUserRepository userRepository )
    {
        UserRepository = userRepository;
    }

    private readonly IUserRepository UserRepository;

    public void SendNoticeEmail( DateTime minDate, DateTime maxDate, etc... )
    {
        var users = GetUsersWithNotices( minDate, maxDate, etc... );

        // send email to each user
    }

    private IEnumerable<User> GetUsersWithNotices( DateTime minDate, DateTime maxDate, etc... )
    {
        return UserRepository.FindAll( u => UserIsValidForNotice( u, minDate, maxDate, etc... ) );
    }

    private bool UserIsValidForNotice( User user, DateTime minDate, DateTime maxDate, etc... )
    {
        return user.Active && !user.Whatever
               && u.JoinDate > minDate && u.JoinDate < maxDate
               && u.Notices.Any( n => n.Active && !n.Something
                                 && Whatever
                                 && etc... ) );
    }
}
公共类电子邮件任务
{
公共电子邮件任务(IUserRepository userRepository)
{
UserRepository=UserRepository;
}
专用只读IUserRepository UserRepository;
公共作废SendNoticeEmail(DateTime minDate、DateTime maxDate等)
{
var users=GetUsersWithNotices(minDate、maxDate等);
//向每个用户发送电子邮件
}
private IEnumerable GetUsersWithNotices(DateTime minDate、DateTime maxDate等)
{
返回UserRepository.FindAll(u=>UserIsValidForNotice(u、minDate、maxDate等);
}
私有bool UserIsValidForNotice(用户用户、DateTime minDate、DateTime maxDate等)
{
返回user.Active&&!user.where
&&u.JoinDate>minDate&&u.JoinDaten.Active&&!n.Something)
&&随便
&&),;
}
}
这会导致NHibernate引发异常:

System.ServiceModel.FaultException`1 was unhandled
  HResult=-2146233087
  Message=Boolean UserIsValidForNotice(User, System.DateTime, System.DateTime)
  Source=Castle.Facilities.WcfIntegration
  StackTrace:
       at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
       at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.InvokeRealProxy(RealProxy realProxy, WcfInvocation wcfInvocation)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.<>c__DisplayClass1.<PerformInvocation>b__0(WcfInvocation wcfInvocation)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex, WcfInvocation wcfInvocation, Action`1 action)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.<>c__DisplayClass4.<ApplyChannelPipeline>b__3()
       at Castle.Facilities.WcfIntegration.WcfInvocation.Proceed()
       at Castle.Facilities.WcfIntegration.RefreshChannelPolicy.Apply(WcfInvocation invocation)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex, WcfInvocation wcfInvocation, Action`1 action)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation invocation, Action`1 action)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation invocation)
       at Castle.Facilities.WcfIntegration.Async.WcfRemotingAsyncInterceptor.PerformInvocation(IInvocation invocation)
       at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.Intercept(IInvocation invocation)
       at Castle.DynamicProxy.AbstractInvocation.Proceed()
       at Castle.Proxies.IEmailServiceProxy.SendNoticeEmail()
       at [Excised]
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
未处理System.ServiceModel.FaultException`1 HResult=-2146233087 Message=Boolean UserIsValidForNotice(User,System.DateTime,System.DateTime) Source=Castle.Facilities.wcfinintegration 堆栈跟踪: 在System.ServiceModel.Channels.ServiceChannel.ThrowiffaultUnderstanding处(消息回复、消息故障、字符串操作、消息版本、故障转换器故障转换器) 位于System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime操作,ProxyRpc&rpc) 在System.ServiceModel.Channels.ServiceChannel.Call(字符串操作、布尔单向、ProxyOperationRuntime操作、对象[]输入、对象[]输出、时间跨度超时) 位于System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage方法调用,ProxyOperationRuntime操作) 位于System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage消息) 位于Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.invokeralproxy(RealProxy RealProxy,wcfinocation wcfinocation) 在Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.c_udisplayClass1.b_u0(wcfinocation-wcfinocation) 位于Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex,wcfinocation,wcfinocation,Action`1 Action) 在Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.c_udisplayClass4.b_u3()中 在Castle.Facilities.wcfinintegration.wcfinocation.procedure()中 在Castle.Facilities.wcfinintegration.RefreshChannelPolicy.Apply(wcfinCallation调用) 位于Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex,wcfinocation,wcfinocation,Action`1 Action) 位于Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation调用,操作'1操作) 在Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation调用)中 位于Castle.Facilities.wcfinintegration.Async.WcfRemotingAsyncInterceptor.PerformInvocation(IInvocation调用) 在Castle.Facilities.wcfinintegration.Proxy.WcfRemotingInterceptor.Intercept(IInvocation调用) 在Castle.DynamicProxy.AbstractInvocation.procedure()中 在Castle.proxy.IEmailServiceProxy.SendNoticeEmail()上 在[切除] 位于System.AppDomain.\u nExecuteAssembly(RuntimeAssembly程序集,字符串[]args) 位于System.AppDomain.ExecuteAssembly(字符串汇编文件、证据汇编安全性、字符串[]args) 在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()上 位于System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态) 位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext、ContextCallback回调、对象状态、布尔值preserveSyncCtx) 在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态,布尔保存SyncCTX) 在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态) 位于System.Threading.ThreadHelper.ThreadStart()处 内部异常: 我想NHibernate转换为SQL太复杂了。

[Edit] 我做了一些额外的研究,最后问了同样的问题,得到了一些很好的答案:

这可能是使用存根而不是Moq的好地方,如下所示:

public class StubRepo : IUserRepository
{
    public IList<User> PersonList { get; set; }

    public IList<User> FindAll(Func<User, bool> q)
    {
        return PersonList.Where(q).ToList();
    }
}
公共类StubRepo:IUserRepository
{
公共IList个人列表{get;set;}
公共IList FindAll(职能q)
{
return PersonList.Where(q.ToList();
}
}
然后,您可以传入一个虚拟的人员列表,并验证返回的人员是否满足您的条件。因为GetUsersWithValidNotices是私有的,所以您可以使用Moq来验证您的电子邮件发送逻辑只被调用了一次。它看起来像这样:

[TestMethod]
public void TestMethod1()
    {
        //Arrange
        var userList = new List<User>();
        userList .Add(new User { Name="Mike", Active = false });
        userList .Add(new User { Name="Mary", Active = true });
        var stubRepo = new StubRepo{ PersonList = userList});

        var emailSender = Mock<IEmailSender>();

         var emailTask = new EmailTask(stubRepo);
        emailTask.EmailSender = emailSender.Object;


        //Action
        emailTask.SendNoticeEmail(.....);

        //Assert - Verify email only sent to the one active user
        emailSender.Verify(x => x.SendEmail(It.IsAny<User>()), Times.Once())

    }
[TestMethod]
公共void TestMethod1()
{
//安排
var userList=新列表();
添加(新用户{Name=“Mike”,Active=false});
添加(新用户{Name=“Mary”,Active=true});
var stubRepo=new stubRepo{PersonList=userList});
var emailSender=Mock();
var emailTask=新的emailTask(stubRepo);
emailTask.EmailSender=EmailSender.Object;
//行动
emailTask.SendN
[TestMethod]
public void TestMethod1()
    {
        //Arrange
        var userList = new List<User>();
        userList .Add(new User { Name="Mike", Active = false });
        userList .Add(new User { Name="Mary", Active = true });
        var stubRepo = new StubRepo{ PersonList = userList});

        var emailSender = Mock<IEmailSender>();

         var emailTask = new EmailTask(stubRepo);
        emailTask.EmailSender = emailSender.Object;


        //Action
        emailTask.SendNoticeEmail(.....);

        //Assert - Verify email only sent to the one active user
        emailSender.Verify(x => x.SendEmail(It.IsAny<User>()), Times.Once())

    }
private IEnumerable<User> GetUsersWithNotices( DateTime minDate, DateTime maxDate, etc... )
{
    return UserRepository.FindAll( u => u.Active && !u.Whatever
                                        && u.JoinDate > minDate && u.JoinDate < maxDate
                                        && u.Notices.Any( n => n.Active && !n.Something
                                                               && Whatever
                                                               && etc... ) );
}