C# 如何在最小起订量中为属性赋值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16816551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 07:51:40  来源:igfitidea点击:

How to assign values to properties in moq?

c#unit-testingmockingmoq

提问by ridermansb

I have a class with a method that returns an object of type User

我有一个带有返回类型对象的方法的类 User

public class CustomMembershipProvider : MembershipProvider
{
    public virtual User GetUser(string username, string password, string email, bool isApproved)
    {
        return new User()
            {
                Name = username
                ,Password = EncodePassword(password)
                ,Email = email
                ,Status = (isApproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente)
                // ...
            };
    }

    // ..
}

Useris a domain object. Note the Idproperty with setter as protected:

User是域对象。请注意setter 为 protectedId属性:

public class User : IAuditable, IUser
{
    public virtual int Id { get; protected set; }
    public virtual string Name { get; set; }
    public virtual string Email { get; set; }
    public virtual UsuarioStatusEnum Status { get; set; }
    public virtual string Password { get; set; }
}

Id is protected because it is generated by the database.

Id 是受保护的,因为它是由数据库生成的。

Test project

测试项目

In my Test project I have a Fake repository with a method Storeto save/update the object:

在我的测试项目中,我有一个 Fake 存储库,其中包含一个Store保存/更新对象的方法:

public void Store(T obj)
{
    if (obj.Id > 0)
        _context[obj.Id] = obj;
    else
    {
        var generateId =  _context.Values.Any() ? _context.Values.Max(p => p.Id) + 1 : 1;
        var stubUser = Mock.Get<T>(obj); // In test, will always mock
        stubUser.Setup(s => s.Id).Returns(generateId);
        _context.Add(generateId, stubUser.Object);
    }
}

In CustomMembershipProviderI have public override MembershipUser CreateUsermethod that calls the GetUserto create a User.
This way, all I have to do is mock the GetUsermethod so that the repository can generate the Id

CustomMembershipProvider我有public override MembershipUser CreateUser调用 的方法GetUser来创建一个User.
这样,我所要做的就是模拟该GetUser方法,以便存储库可以生成Id

var membershipMoq = new Mock<CustomMembershipProvider>();
membershipMoq.CallBase = true;
membershipMoq
    .Setup(p => p.GetUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
    .Returns<string, string, string, bool>( (username, password, email, isAproved) => {
        var moqUser = new Mock<User>();
        moqUser.Object.Name = username;
        moqUser.Object.Password = password;
        moqUser.Object.Email = email;
        moqUser.Object.Status = (isAproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente);
        return moqUser.Object;
    });
_membershipProvider = membershipMoq.Object;

Problem

问题

In theory everything is correct. When CreateUsercall 'GetUser' to create a user, the user will return Mock filled;

理论上一切都是正确的。当CreateUser调用'GetUser'创建用户时,用户将返回Mock填充;

[TestMethod]
public void CreateUser_deve_criar_usuario_no_repositorio()
{
    // Act
    MembershipCreateStatus status;
    var  usr = _membershipProvider.CreateUser(
        _fixture.Create<string>(),
        _fixture.Create<string>(),
        _fixture.Create<string>(),
        null, null, true, null,
        out status);

    // usr should have name, email password filled. But not!

    // Assert
    status.Should().Be(MembershipCreateStatus.Success);
}

The problem is that Email, Name, Password are empty (with default values)!

问题是电子邮件、名称、密码为空(使用默认值)!

enter image description here

在此处输入图片说明

采纳答案by Sunny Milenov

The way you prepare the mocked user is the problem.

您准备模拟用户的方式是问题所在。

moqUser.Object.Name = username;

will not set the name, unless you have setup the mock properly. Try this before assigning values to properties:

不会设置名称,除非您正确设置了模拟。在为属性赋值之前试试这个:

moqUser.SetupAllProperties();

This method will prepare all properties on the mock to be able to record the assigned value, and replay it later (i.e. to act as real property).

此方法将准备模拟上的所有属性,以便能够记录分配的值,并在稍后重播(即充当真实属性)。

You can also use SetupProperty()method to set up individual properties to be able to record the passed in value.

您还可以使用SetupProperty()方法来设置各个属性,以便能够记录传入的值。

Another approach is:

另一种方法是:

var mockUser = Mock.Of<User>( m =>
    m.Name == "whatever" &&
    m.Email == "[email protected]"); 

return mockUser;

回答by Sergey Berezovskiy

I think you are missing purpose of mocking. Mocks used to mock dependencies of class you are testing:

我认为你缺少嘲笑的目的。用于模拟您正在测试的类的依赖项的模拟:

enter image description here

在此处输入图片说明

System under test (SUT) should be tested in isolation (i.e. separate from other units). Otherwise errors in dependencies will cause your SUTs tests to fail. Also you should not write tests for mocks. That gives you nothing, because mocks are not production code. Mocks are not executed in your application.

被测系统 (SUT) 应单独测试(即与其他单元分开)。否则依赖项中的错误将导致您的 SUT 测试失败。此外,您不应该为模拟编写测试。那什么也没给你,因为模拟不是生产代码。模拟不在您的应用程序中执行。

So, you should mock CustomMembershipProvideronly if you are testing some unit, which depends on it (BTW it's better to create some abstraction like interface ICustomMembershipProviderto depend on).

因此,CustomMembershipProvider只有在测试某个依赖于它的单元时才应该模拟(顺便说一句,最好创建一些抽象,如ICustomMembershipProvider要依赖的接口)。

Or, if you are writing tests for CustomMembershipProviderclass, then it should not be mocked - only dependencies of this provider should be mocked.

或者,如果您正在为CustomMembershipProvider类编写测试,则不应模拟它 - 仅应模拟此提供程序的依赖项。