模拟一种测试方法

cod*_*ife 9 c# unit-testing moq mocking visual-studio

试图模拟在另一个方法中调用的方法.

public virtual bool hello(string name, int age)
{

    string lastName = GetLastName();
}

 public virtual string GetLastName() 
    {
        return "xxx"; 
    }

 Mock<program> name= new Mock<program>();
 name.Setup(x => x.GetLastName()).Returns("qqq");
Run Code Online (Sandbox Code Playgroud)

我希望方法GetLastName始终返回"qqq".

Kri*_*ner 9

这应该有效,假设这些是完整的方法实现

public class MyProgram
{

    public bool hello(string name, int age)
    {
        string lastName = GetLastName();

        return string.Format("hello {0}", lastName);
    }

    public virtual string GetLastName() 
    {
        return "xxx"; 
    }
}

public class MyProgramTests
{

    [TestMethod]
    public void MyTest()
    {

        string stringToReturn = "qqq";
        Mock<MyProgram> name = new Mock<MyProgram>();
        name.CallBase = true;
        name.Setup(x => x.GetLastName()).Returns(stringToReturn );

        var results = name.Object.hello(It.IsAny<string>(), It.IsAny<int>());

        string expected = string.Format("hello {0}", results);

        Assert.AreEqual(expected, results);
    }
}
Run Code Online (Sandbox Code Playgroud)

我仍然不太关注你的评论:

参数对Mock的真正含义是什么?是?对不起,我不太懂语法.为了澄清,mock意味着当我在我的代码中放置断点时,断点应该跳过我正在嘲笑的方法.我对吗?

Mock<T> 允许你模拟一种类型T- T作为一个通用指标,也意味着几乎任何类的东西.在传统中,你会嘲笑一个interface,而不是一个实际的class,但在上面的例子中,我们是在嘲笑一个类.对于发布的样本单元测试,单元测试的目的是测试实现hello(string, int).我们知道hello(string, int)依赖于该类中的另一个方法GetLastName(). GetLastName()实施虽然重要,但对单元测试的范围并不重要hello(string, int).出于这个原因,我们模拟调用及其返回 - 以便测试功能hello(string, int)而不必担心其依赖项的实现.

我已经用实际的类名包围了上面的内容,希望能让我们更明显地嘲笑这个类MyProgram并提供一个新的实现(模拟)GetLastName()

谢谢你的回答.如果我想测试调用另一个调用另一个方法的方法的方法怎么办?例如.如果方法hello调用另一个方法怎么办?

同样的原则也适用于您构建单元测试时(假设它们是单元测试,而不是集成测试或其他测试),您总是希望专注于测试一种公共方法. 单元测试和集成测试之间有什么区别?

public class Foo
{

    public string Bar()
    {
        return string.Format("{0}Bar", Baz(5));;
    }

    public virtual string Baz(int someNumber)
    {
        return string.Format("{0}Baz", DoStuff(someNumber).ToString());
    }

    public virtual int DoStuff(int someNumber)
    {
        return someNumber+1;
    }

}
Run Code Online (Sandbox Code Playgroud)

如果我们进行单元测试,Bar()我们不关心实施Baz(int)甚至更糟DoStuff(int).注意:我们不关心的实现,我们关心他们返回值.从Bar()s的角度来看,唯一重要的是Baz(int)返回一个字符串.什么字符串?Bar()单元测试无关紧要.

样品测试Bar():

[TestMethod]
public void Bar_ReturnsBazValueWithBarAppended
{
    // Arrange
    string testBazReturn = "test";
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.Baz(It.IsAny<int>())
        .Returns(testBazReturn);

    // Act
    var results = mock.Object.Bar();

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", testBazReturn, "Bar"), results);
    mock.Verify(v => v.Baz(It.IsAny<int>())); // Verifies that Baz was called
}
Run Code Online (Sandbox Code Playgroud)

请注意,在上面,我们实际的实现Baz(int),DoStuff(int)并不重要,因为我们无视实际的实现Baz(int),DoStuff(int)甚至没有发挥作用.

现在,如果我们要测试Baz(int)我们只是遵循相同的心态:

[TestMethod]
public void Baz_ReturnsDoStuffValueWithBazAppended
{
    // Arrange
    int testDoStuffReturn = 1;
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.DoStuff(It.IsAny<int>())
        .Returns(testDoStuffReturn);

    // Act
    var results = mock.Object.Baz(5);

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", results, "Baz"), results); // Validates the result
    mock.Verify(v => v.DoStuff(It.IsAny<int>())); // Verifies that DoStuff was called
}
Run Code Online (Sandbox Code Playgroud)

在上面,既然我们是单元测试Baz(int),我们不关心,我们Bar()唯一关心的DoStuff(int)是它返回一个值(但不是它如何到达该值.)

最后DoStuff(int):

[TestMethod]
public void DoStuff_ReturnsParameterPlusOne()
{
    // Arrange
    Foo foo = new Foo();
    int passed = 1;
    int expected = passed + 1;

    // Act
    var results = foo.DoStuff(passed);

    // Assert
    Assert.AreEqual(expected, results);
}
Run Code Online (Sandbox Code Playgroud)