Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.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

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# 单元测试中MOQ的正确使用_C#_Unit Testing_Moq_Xunit_Xunit.net - Fatal编程技术网

C# 单元测试中MOQ的正确使用

C# 单元测试中MOQ的正确使用,c#,unit-testing,moq,xunit,xunit.net,C#,Unit Testing,Moq,Xunit,Xunit.net,鉴于以下情况,这是MOQ的正确使用吗?我对“嘲弄”、“存根”、“伪造”等都是很陌生的,我只是想把我的头绕在它周围 我的理解是,这个mock提供了一个已知的结果,所以当我使用它测试这个服务时,服务的反应是否正常 public interface IRepository<T> where T : class { void Add(T entity); void Delete(T entity); void Update(T entity); IQuerya

鉴于以下情况,这是MOQ的正确使用吗?我对“嘲弄”、“存根”、“伪造”等都是很陌生的,我只是想把我的头绕在它周围

我的理解是,这个mock提供了一个已知的结果,所以当我使用它测试这个服务时,服务的反应是否正常

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    IQueryable<T> Query();
}

public interface ICustomerService
{
    void CreateCustomer(Customer customer);
    Customer GetCustomerById(int id);
}

public class Customer
{
    public int Id { get; set; }

}

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer> customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        this.customerRepository = customerRepository;
    }

    public Customer GetCustomerById(int id)
    {
        return customerRepository.Query().Single(x => x.Id == id);
    }

    public void CreateCustomer(Customer customer)
    {
        var existingCustomer = customerRepository.Query().SingleOrDefault(x => x.Id == customer.Id);

        if (existingCustomer != null)
            throw new InvalidOperationException("Customer with that Id already exists.");

        customerRepository.Add(customer);
    }
}

public class CustomerServiceTests
    {
        [Fact]
        public void Test1()
        {
            //var repo = new MockCustomerRepository();
            var repo = new Mock<IRepository<Customer>>();
            repo.Setup(x => x.Query()).Returns(new List<Customer>() { new Customer() { Id = 1 }}.AsQueryable());

            var service = new CustomerService(repo.Object);

            Action a = () => service.CreateCustomer(new Customer() { Id = 1 });

            a.ShouldThrow<InvalidOperationException>();

        }
    }
公共接口i假设,其中T:class
{
无效添加(T实体);
无效删除(T实体);
无效更新(T实体);
IQueryable查询();
}
公共接口ICCustomerService
{
无效创建客户(客户);
客户GetCustomerById(内部id);
}
公共类客户
{
公共int Id{get;set;}
}
公共类CustomerService:ICCustomerService
{
私有只读存储客户存储;
公共客户服务(IRepository customerRepository)
{
this.customerRepository=customerRepository;
}
公共客户GetCustomerById(内部id)
{
返回customerRepository.Query().Single(x=>x.Id==Id);
}
公共无效CreateCustomer(客户)
{
var existingCustomer=customerRepository.Query().SingleOrDefault(x=>x.Id==customer.Id);
if(existingCustomer!=null)
抛出新的InvalidOperationException(“具有该Id的客户已经存在”);
customerRepository.Add(客户);
}
}
公共类CustomerService测试
{
[事实]
公共void Test1()
{
//var repo=new MockCustomerRepository();
var repo=new Mock();
repo.Setup(x=>x.Query()).Returns(new List(){new Customer(){Id=1}}}.AsQueryable());
var服务=新客户服务(repo.Object);
操作a=()=>service.CreateCustomer(新客户(){Id=1});
a、 shouldtown();
}
}
我正在使用xUnit、FluentAssertions和MOQ

我的理解是这个模拟提供了一个已知的结果, 那么,当我使用它测试这个服务时,服务的反应是否正常

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    IQueryable<T> Query();
}

public interface ICustomerService
{
    void CreateCustomer(Customer customer);
    Customer GetCustomerById(int id);
}

public class Customer
{
    public int Id { get; set; }

}

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer> customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        this.customerRepository = customerRepository;
    }

    public Customer GetCustomerById(int id)
    {
        return customerRepository.Query().Single(x => x.Id == id);
    }

    public void CreateCustomer(Customer customer)
    {
        var existingCustomer = customerRepository.Query().SingleOrDefault(x => x.Id == customer.Id);

        if (existingCustomer != null)
            throw new InvalidOperationException("Customer with that Id already exists.");

        customerRepository.Add(customer);
    }
}

public class CustomerServiceTests
    {
        [Fact]
        public void Test1()
        {
            //var repo = new MockCustomerRepository();
            var repo = new Mock<IRepository<Customer>>();
            repo.Setup(x => x.Query()).Returns(new List<Customer>() { new Customer() { Id = 1 }}.AsQueryable());

            var service = new CustomerService(repo.Object);

            Action a = () => service.CreateCustomer(new Customer() { Id = 1 });

            a.ShouldThrow<InvalidOperationException>();

        }
    }
这句话是正确的-单元测试应该验证您正在测试的类(在本例中,
CustomerService
)是否显示了您想要的行为。它的目的不是验证其依赖项是否按预期运行(在本例中,
IRepository

您的测试很好*-您正在为
IRepository
设置模拟,并将其注入测试中的系统,并验证
CustomerService.CreateCustomer()
函数是否显示了您期望的行为

*测试的总体设置很好,但我不熟悉xUnit,所以最后两行的语法对我来说是陌生的,但从语义上看,它看起来是正确的。为了便于参考,您可以这样做NUnit中的最后两行:

Assert.Throws<InvalidOperationException>(() => service.CreateCustomer(...));
Assert.Throws(()=>service.CreateCustomer(…);
我的理解是这个模拟提供了一个已知的结果, 那么,当我使用它测试这个服务时,服务的反应是否正常

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    IQueryable<T> Query();
}

public interface ICustomerService
{
    void CreateCustomer(Customer customer);
    Customer GetCustomerById(int id);
}

public class Customer
{
    public int Id { get; set; }

}

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer> customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        this.customerRepository = customerRepository;
    }

    public Customer GetCustomerById(int id)
    {
        return customerRepository.Query().Single(x => x.Id == id);
    }

    public void CreateCustomer(Customer customer)
    {
        var existingCustomer = customerRepository.Query().SingleOrDefault(x => x.Id == customer.Id);

        if (existingCustomer != null)
            throw new InvalidOperationException("Customer with that Id already exists.");

        customerRepository.Add(customer);
    }
}

public class CustomerServiceTests
    {
        [Fact]
        public void Test1()
        {
            //var repo = new MockCustomerRepository();
            var repo = new Mock<IRepository<Customer>>();
            repo.Setup(x => x.Query()).Returns(new List<Customer>() { new Customer() { Id = 1 }}.AsQueryable());

            var service = new CustomerService(repo.Object);

            Action a = () => service.CreateCustomer(new Customer() { Id = 1 });

            a.ShouldThrow<InvalidOperationException>();

        }
    }
这句话是正确的-单元测试应该验证您正在测试的类(在本例中,
CustomerService
)是否显示了您想要的行为。它的目的不是验证其依赖项是否按预期运行(在本例中,
IRepository

您的测试很好*-您正在为
IRepository
设置模拟,并将其注入测试中的系统,并验证
CustomerService.CreateCustomer()
函数是否显示了您期望的行为

*测试的总体设置很好,但我不熟悉xUnit,所以最后两行的语法对我来说是陌生的,但从语义上看,它看起来是正确的。为了便于参考,您可以这样做NUnit中的最后两行:

Assert.Throws<InvalidOperationException>(() => service.CreateCustomer(...));
Assert.Throws(()=>service.CreateCustomer(…);

在我看来,测试很好,模拟只是提供了一个假存储库,它只为测试返回硬编码的答案,因此测试只关心您正在测试的服务,而不处理现实生活中的数据库或其他任何东西,因为您不在这里测试它

我只想在测试中添加一项内容,使其更加完整在模拟上设置方法调用时,请确保被测系统确实调用了它们。毕竟,服务应该向回购请求某些对象,并仅在某个返回值下抛出。Moq特别为此提供了语法:

repo.VerifyAll();

这只需检查您之前放置的设置是否至少被调用过一次。这可以防止服务在不调用repo的情况下立即抛出异常的错误(在像您这样的示例中很容易发现,但是对于复杂的代码,很容易错过调用)。有了这句话,在测试结束时,如果您的服务没有调用repo请求列表(并使用特定的参数集),测试也会失败,即使异常被正确抛出。

测试在我看来很好,mock只是提供了一个假存储库,它只为测试返回硬编码的答案,因此,测试只关心您正在测试的服务,而不涉及实际数据库或其他任何东西,因为您没有在这里测试它

我只想在测试中添加一项内容,使其更加完整在模拟上设置方法调用时,请确保被测系统确实调用了它们。毕竟,服务应该向回购请求某些对象,并仅在某个返回值下抛出。Moq特别为此提供了语法:

repo.VerifyAll();
这只需检查您之前放置的设置是否至少被调用过一次。这可以防止服务在不调用repo的情况下立即抛出异常的错误(在像您这样的示例中很容易发现,但是对于复杂的代码,很容易错过调用)。有了这个