c# - 没有 setter 的模拟对象

标签 c# .net unit-testing moq

我正在使用只有一堆 {get;} 的第三方库 UserContext

public static UserContext Current { get; }
public UserContact CurrentContact { get; }
public string UserContactName { get; }

在我的代码中,它只是像这样返回 CurrentUser:

void DoSomething(){
    UserContext Current = UserContext.Current; // 3rd party lib
}

我无法为单元测试设置一个新的假对象。所以,为了在我的代码中模拟这个,我做了以下事情:

创建了一个继承自 UserContext 并覆盖当前属性的子类:

public class UserContextFake : UserContext
{
    public new UserContext Current { get; set; }
}

然后创建一个接口(interface)和一个包装器:

public class UserContextWrapper : IUserContext
{
    public UserContextWrapper()
    {
        userContext = UserContext.Current;
    }

    public UserContextWrapper(UserContext context)
    {
        userContext = context;
    }

    private readonly UserContext userContext;

    public UserContext Current
    {
        get { return userContext; }
    }
}

现在我可以将 userContextWrapper 注入(inject)到我的类中。我公开了两个构造函数:一个将 UserContext.Current(第 3 方库) session 内容用于生产代码,以及一个可以接收自定义 UserContextFake 的构造函数。在 IoC 中,我将 IUserContext 映射到 UserContext

问题:如果 CurrentContact 不在界面中而是 UserContext 的属性 (UserContext.CurrentContact),我该如何模拟它

最佳答案

您不能为整个 3dr 派对库创建一个界面吗?然后实现此接口(interface)并将此类用作第 3 方库的包装器。方法。在被测类中然后添加例如可用于注入(inject)接口(interface)模拟的属性。示例(未经测试)。

public interface IThirdPartyLibraryWrapper
{
    UserContext Current { get; }
    UserContact CurrentContact { get; }
    string UserContactName { get; }
}

public class ThirdPartyLibraryWrapper 
    : IThirdPartyLibraryWrapper
{
    public UserContext Current 
    { 
        get { /* return Current from third party library */}
    }

    public UserContact CurrentContact 
    { 
        get{ /* return CurrentContact from third party library */} 
    }

    public string UserContactName 
    { 
        get{ /* return UserContactName from third party library */} 
    }
}

public class ClassUnderTest
{
    // Inject 3rd party lib
    private IThirdPartyLibraryWrapper _library;
    public virtual IThirdPartyLibraryWrapper Library
    {
        get
        {
            if (_library == null)
                _library = new ThirdPartyLibraryWrapper();
            return _library;
        }
        set
        {
            if (value != null)
                _library = value;
        }
    }

    void DoSomething(){
        UserContext Current = Library.Current; 
    }
}

[TestMethod]
public void DoSomething_WhenCalled_UsesLibraryMock()
{
    // Arrange
    UserContext fakeUserContext = new UserContext();
    Mock<IThirdPartyLibraryWrapper> libraryMock = new Mock<IThirdPartyLibraryWrapper>();
    libraryMock.Setup(l => l.Current).Returns(fakeUserContext);
    ClassUnderTest cut = new ClassUnderTest();
    cut.Library = libraryMock.Object;

    // Act
    cut.DoSomething()

    // Assert
    // ...
}

关于c# - 没有 setter 的模拟对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35298673/

相关文章:

c# - 使用三元语法将参数设置为 DBNull.Value 会出错?

c# - Continuous For Each Loop 不会停止插入到 SQL Server

.net - 在Visual Studio调试器值 "{ }"中是什么意思?

c# - 选择匿名类型可以为空吗?

c# - 在 C# 中究竟什么时候执行事件?

.net - elasticsearch c#/.net客户端推荐

java - 尝试模拟 get 类时出现 Mockito UnfinishedStubbingException

php - Symfony 单元测试自定义事件监听器

c# - 什么相当于 C# 中的 JUnit?

c# - 调试语句执行计数器