模拟测试方法 [英] Mock a method for test

查看:64
本文介绍了模拟测试方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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");

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

解决方案

这应该可行,假设它们是完整的方法实现

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);
    }
}

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

该参数实际上是什么意思?Mock应该是什么?是?对不起,我不太了解语法.澄清一下,模拟意味着当我在代码中放置断点时,断点应跳过我正在模拟的方法.我说的对吗?

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

我在上面用实际的类名将其括起来,希望可以使我们更清楚地了解类MyProgram并提供GetLastName()的新实现(模拟)

感谢您的回答.如果我想测试一个调用另一个方法的方法,该方法又调用另一个方法?例如.如果方法问候调用了另一种方法怎么办?

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

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;
    }

}

如果我们正在对Bar()进行单元测试,则我们不关心Baz(int)的实现,甚至不关心DoStuff(int)的实现.注意 我们不在乎实现 ,我们 要做 关心它们返回值.从Bar()的角度来看,唯一重要的是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
}

在上述声明中,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
}

在上面,我们现在正在对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);
}

Trying to mock a method that is called within another method.

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");

I want the method GetLastName to always return "qqq".

解决方案

This should work, assuming those are the full method implementations

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);
    }
}

I'm still not quite following your comment:

What does the parameter really mean of Mock What should ?? be? excuse me, I don't quite understand the syntax. To clarify, mock means that when I put break points in my code I the breakpoints should skip the methods that I am mocking. Am I right?

Mock<T> allows you to mock a type of T - T being a generic indicator, also meaning pretty much anything that's a class. In the traditional, you would be mocking an interface, not an actual class, but in the example above, we're mocking a class. For the sample unit test posted, the purpose of the unit test is to test the implementation of hello(string, int). We know that hello(string, int) relies on another method within that class called GetLastName(). GetLastName()s implementation, while important, is not important to the scope of unit testing hello(string, int). For this reason, we mock the call and its return - in order to test the functionality of hello(string, int) without having to worry about its dependency's implementation.

I have surrounded the above with actual class names to hopefully make it more obvious that we're mocking the class MyProgram and providing a new implementation (mock) of GetLastName()

Thanks for the answer. What if I want to test a method that calls another method that calls another method? For eg. what if the method hello called another method?

The same principle applies, when you're building your unit tests (assuming they are unit tests, and not integration tests or other, you always want to concentrate on testing one public method. What's the difference between unit and integration tests?

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;
    }

}

If we're unit testing Bar() we do not care about the implementation of Baz(int) or even worse DoStuff(int). Note we don't care about the implementation, we do care that they return values. From Bar()s perspective, the only thing that is important is the Baz(int) returns a string. What string? It doesn't matter to Bar()s unit test.

Sample test for 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
}

Notice in the above, our actual implementations of Baz(int), and DoStuff(int) do not matter, as we are disregarding the actual implementation of Baz(int), and DoStuff(int) doesn't even come into play.

Now, if we were to test Baz(int) we just follow the same mentality:

[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
}

In the above, now that we're unit testing Baz(int), we don't care about Bar(), and the only thing we care about in DoStuff(int) is that it returns a value (but not how it arrives at that value.)

And finally 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);
}

这篇关于模拟测试方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆