C# Autofac mock-如何从依赖项中的特定方法设置/伪造数据?

C# Autofac mock-如何从依赖项中的特定方法设置/伪造数据?,c#,moq,autofac,xunit,C#,Moq,Autofac,Xunit,我对单元测试、Autofac和Mock都是新手,所以很可能,这相对容易,但我很难弄明白 我有一个类systemundtest,它有一个依赖项,还有两个方法GetValueOne和GetValueTwo public class SystemUnderTest : ISystemUnderTest { private readonly IDependency _dependency; public SystemUnderTest(IDependency dependency)

我对单元测试、Autofac和Mock都是新手,所以很可能,这相对容易,但我很难弄明白

我有一个类
systemundtest
,它有一个依赖项,还有两个方法
GetValueOne
GetValueTwo

public class SystemUnderTest : ISystemUnderTest
{
    private readonly IDependency _dependency;

    public SystemUnderTest(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string GetValueOne()
    {
        return _dependency.GetValueOne();
    }

    public string GetValueTwo()
    {
        return _dependency.GetValueTwo();
    }
}

public interface ISystemUnderTest
{
    string GetValueOne();
    string GetValueTwo();
}
这些方法从依赖项获取数据

public class Dependency : IDependency
{
    public string GetValueOne()
    {
        return "get-value-one";
    }
    public string GetValueTwo()
    {
        return "get-value-two";
    }
}

public interface IDependency
{
    string GetValueOne();
    string GetValueTwo();
}
我试图从其中一个方法(即“
GetValueTwo
”)中伪造数据,因此它返回的是
“预期值”
,而不是依赖项通常返回的
“GetValueTwo”

[Fact]
public async Task Test_SystemUnderTest()
{
    using (var mock = AutoMock.GetLoose())
    {
        // Setup
        mock.Mock<IDependency>().Setup(x => x.GetValueTwo()).Returns("expected value");

        // Configure
        mock.Provide<IDependency, Dependency>();

        // Arrange - configure the mock
        var sut = mock.Create<SystemUnderTest>();

        // Act
        var actual_GetValueOne = sut.GetValueOne();
        var actual_GetValueTwo = sut.GetValueTwo();

        // Assert - assert on the mock
        Assert.Equal("get-value-one", actual_GetValueOne);
        Assert.Equal("expected value", actual_GetValueTwo);
    }
}
[事实]
公共异步任务测试\u SystemUnderTest()
{
使用(var mock=AutoMock.GetLoose())
{
//设置
mock.mock().Setup(x=>x.GetValueTwo())。返回(“预期值”);
//配置
mock.Provide();
//排列-配置模拟
var sut=mock.Create();
//表演
var-actual_GetValueOne=sut.GetValueOne();
var actual_GetValueTwo=sut.GetValueTwo();
//Assert-在模拟上断言
Assert.Equal(“获取值一”,实际值一);
Assert.Equal(“预期值”,实际值二);
}
}
我测试的第一部分,设置,似乎没有任何效果,可能是因为我做了一些基本的错误


有人知道如何节省时间吗?

不是编写单元测试的专家,但我非常确定,通过使用带有两个类型参数的
Provide
,您可以覆盖以前所做的
设置部分。根据我的理解,应该使用
Provide
方法来提供您自己的目标接口的模拟实现,因此对同一依赖项同时使用带有两个类型参数的
Provide
Setup
是没有意义的

因此,您可以修改
依赖关系
实现的
GetValueTwo
以返回
的“期望值”
,并使用未修改的其余代码,也可以将模拟实例提供给
提供
方法,其中包含一个类型参数,这两个方法都是以前设置的,如下所示:

    [Fact]
    public async Task Test_SystemUnderTest()
    {
        using (var mock = AutoMock.GetLoose())
        {
            var mockedDependency = mock.Mock<IDependency>();

            // Setup
            mockedDependency.Setup(x => x.GetValueOne()).Returns("get-value-one");
            mockedDependency.Setup(x => x.GetValueTwo()).Returns("expected value");

            // The following line is not even necessary
            mock.Provide<IDependency>(mockedDependency.Object);

            // Arrange - configure the mock
            var sut = mock.Create<SystemUnderTest>();

            // Act
            var actual_GetValueOne = sut.GetValueOne();
            var actual_GetValueTwo = sut.GetValueTwo();

            // Assert - assert on the mock
            Assert.Equal("get-value-one", actual_GetValueOne);
            Assert.Equal("expected value", actual_GetValueTwo);
        }
    }
[事实]
公共异步任务测试\u SystemUnderTest()
{
使用(var mock=AutoMock.GetLoose())
{
var mockedDependency=mock.mock();
//设置
mockedDependency.Setup(x=>x.GetValueOne())。返回(“获取值一”);
mockedDependency.Setup(x=>x.GetValueTwo())。返回(“预期值”);
//下面的一行甚至不是必需的
mock.Provide(mockedDependency.Object);
//排列-配置模拟
var sut=mock.Create();
//表演
var-actual_GetValueOne=sut.GetValueOne();
var actual_GetValueTwo=sut.GetValueTwo();
//Assert-在模拟上断言
Assert.Equal(“获取值一”,实际值一);
Assert.Equal(“预期值”,实际值二);
}
}

依赖关系
实现的成员需要具有虚拟成员,以便在执行部分模拟时能够覆盖这些成员

public class Dependency : IDependency {
    public virtual string GetValueOne() {
        return "get-value-one";
    }
    public virtual string GetValueTwo() {
        return "get-value-two";
    }
}
然后,与另一个答案中的建议类似,您将模拟实现,确保使其能够调用基本成员,并且只设置需要覆盖的成员

public void Test_SystemUnderTest() {
    using (var mock = AutoMock.GetLoose()) {
        // Setup
        var dependency = mock.Mock<Dependency>();
        dependency.CallBase = true;
        dependency.Setup(x => x.GetValueTwo()).Returns("expected value");

        // Configure
        mock.Provide<IDependency>(dependency.Object);

        // Arrange - configure the mock
        var sut = mock.Create<SystemUnderTest>();

        // Act
        var actual_GetValueOne = sut.GetValueOne();
        var actual_GetValueTwo = sut.GetValueTwo();

        // Assert - assert on the mock
        Assert.AreEqual("get-value-one", actual_GetValueOne);
        Assert.AreEqual("expected value", actual_GetValueTwo);
    }
}
public void Test\u SystemUnderTest(){
使用(var mock=AutoMock.GetLoose()){
//设置
var dependency=mock.mock();
dependency.CallBase=true;
Setup(x=>x.GetValueTwo())。返回(“期望值”);
//配置
mock.Provide(dependency.Object);
//排列-配置模拟
var sut=mock.Create();
//表演
var-actual_GetValueOne=sut.GetValueOne();
var actual_GetValueTwo=sut.GetValueTwo();
//Assert-在模拟上断言
AreEqual(“获取值一”,实际值一);
Assert.AreEqual(“预期值”,实际值二);
}
}

如果需要模拟的实现成员可以被覆盖(即
virtual
),则上述操作将通过。

configure/provide将覆盖设置。为什么要提供依赖性实现呢?我注意到了一些事情。如果没有等待,为什么测试是异步的?@Nkosi简化了这个问题的代码,忘记了删除异步测试。这是一个有趣的问题。我建议您注意我是如何编辑/重新格式化问题的,以便更好地阅读流程和理解您的问题。您可以完全删除“提供”,因为您已经在上设置了所有成员mock@Nkosi是的,刚刚测试过,在这种情况下,不需要提供all@JimmieAndersson实现的成员是虚拟的吗?@DejanJanjušević谢谢,但我不想在依赖接口上设置所有方法,因为我想在SystemUnderTest实现中使用/测试的其他方法中有很多逻辑。这就是为什么我试图提供IDependency的特定实现,所以它会使用这些方法,然后我只想设置特定的方法。@Nkosi它们不是虚拟的