Testing 什么';模拟和模拟的区别是什么;树桩?

Testing 什么';模拟和模拟的区别是什么;树桩?,testing,mocking,stub,Testing,Mocking,Stub,我读过很多关于测试中模拟与存根的文章,包括但仍然不理解其中的区别。模拟只是测试行为,确保调用某些方法。 存根是特定对象的可测试版本(本身) 苹果方式是什么意思?存根是一个简单的假对象。它只是确保测试顺利运行。 模仿是更聪明的存根。您验证您的测试是否通过了它。存根 我相信最大的区别是你已经用预定的行为写了一个存根。因此,您将拥有一个实现依赖关系的类(最有可能是抽象类或接口),这些依赖关系是您为了测试目的而伪造的,而这些方法只会被设置的响应打断。他们不会做任何花哨的事情,您可能已经在测试之外为其编写

我读过很多关于测试中模拟与存根的文章,包括但仍然不理解其中的区别。

模拟只是测试行为,确保调用某些方法。 存根是特定对象的可测试版本(本身)


苹果方式是什么意思?

存根是一个简单的假对象。它只是确保测试顺利运行。
模仿是更聪明的存根。您验证您的测试是否通过了它。

存根

我相信最大的区别是你已经用预定的行为写了一个存根。因此,您将拥有一个实现依赖关系的类(最有可能是抽象类或接口),这些依赖关系是您为了测试目的而伪造的,而这些方法只会被设置的响应打断。他们不会做任何花哨的事情,您可能已经在测试之外为其编写了存根代码

Mock

模拟测试是测试的一部分,你必须根据自己的期望进行设置。模拟不是以预先确定的方式设置的,所以您有代码在测试中进行模拟。模拟在某种程度上是在运行时确定的,因为设置期望的代码必须在执行任何操作之前运行

模拟和存根之间的差异

使用mock编写的测试通常遵循
initialize->set expections->exercise->verify
模式进行测试。而预写存根将遵循
初始化->练习->验证

模拟和存根之间的相似性


两者的目的都是为了消除测试类或函数的所有依赖关系,从而使您的测试更集中,更简单。

存根不会让您的测试失败,mock can。

在本课程中,他们给出了以下术语的定义:

存根

用于用返回指定结果的代码替换方法

嘲弄

一个存根,其断言方法被调用


因此,正如肖恩·科本哈(Sean Copenhaver)在他的回答中所描述的,不同之处在于Mock设定了期望(即,对他们是否或如何被呼叫做出断言)。

我认为他们之间最重要的区别是他们的意图

让我试着在《为什么存根》和《为什么模仿》中解释一下

假设我正在为我的MacTwitter客户端的公共时间线控制器编写测试代码

下面是测试示例代码

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB:到twitterapi的网络连接非常慢,这使得我的测试很慢。我知道它会返回时间线,所以我制作了一个模拟HTTPTwitterAPI的存根,这样我的测试将运行得非常快,即使我离线也可以运行测试
  • MOCK:我还没有编写任何UI方法,我也不确定需要为UI对象编写哪些方法。我希望通过编写测试代码来了解控制器将如何与ui对象协作
通过编写mock,您可以通过验证是否满足期望来发现对象协作关系,而存根只模拟对象的行为

如果您想了解更多关于mock的知识,我建议您阅读本文:

前言 有几种对象的定义,它们不是真实的。一般术语为双倍测试。该术语包括:存根模拟

参考文献 根据:

  • Dummy对象被传递,但从未实际使用过。通常它们只是用来填充参数列表
  • Fake对象实际上有工作实现,但通常会采取一些快捷方式,使其不适合生产(内存中的数据库就是一个很好的例子)
  • 存根为测试期间拨打的电话提供固定答案,通常对测试程序之外的任何内容都没有响应。存根还可以记录有关呼叫的信息,例如电子邮件网关存根,它可以记住它“发送”的消息,或者可能只记录它“发送”的消息数
  • mock就是我们在这里讨论的内容:对象预先编程,并带有期望值,这些期望值形成了它们期望接收的调用的规范
风格 模拟与存根=行为测试与状态测试

原则 根据每个测试只测试一件事情的原则,一个测试中可能有几个存根,但通常只有一个模拟

生命周期 使用存根的测试生命周期:

  • 设置-准备正在测试的对象及其存根协作者
  • 练习-测试功能
  • 验证状态-使用断言检查对象的状态
  • 拆卸-清理资源
  • 模拟的测试生命周期:

  • 设置数据-准备正在测试的对象
  • 设置期望值-在主要对象正在使用的模拟中准备期望值
  • 练习-测试功能
  • 验证期望值-验证是否在模拟中调用了正确的方法
  • 验证状态-使用断言检查对象的状态
  • 拆卸-清理资源
  • 总结 模拟和存根测试都给出了问题的答案:结果是什么?


    模拟测试也感兴趣:结果是如何实现的?如果将其与调试进行比较:

    存根类似于确保方法返回正确的值

    Mock实际上就像是进入该方法,在返回正确的值之前确保里面的所有内容都是正确的


    存根帮助我们运行测试。怎么用?它给出了有助于运行测试的值。这些价值观本身并不真实,我们创造了这些价值观
    namespace UnitTestProject2
    {
        using Microsoft.VisualStudio.TestTools.UnitTesting;
        using Moq;
        [TestClass]
        public class UnitTest1
        {
            /// <summary>
            /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
            /// </summary>
            [TestMethod]
            public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
            {
                // Arrange 
                var mockEntityRepository = new Mock<IEntityRepository>();
                mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
    
                var entity = new EntityClass(mockEntityRepository.Object);
                // Act 
                var name = entity.GetNameWithPrefix(12);
                // Assert
                mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
            }
            /// <summary>
            /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
            /// </summary>
            [TestMethod]
            public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
            {
                // Arrange 
                var mockEntityRepository = new Mock<IEntityRepository>();
                mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
                var entity = new EntityClass(mockEntityRepository.Object);
                // Act 
                var name = entity.GetNameWithPrefix(0);
                // Assert
                mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
            }
            /// <summary>
            /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
            /// </summary>
            [TestMethod]
            public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
            {
                // Arrange 
                var stubEntityRepository = new Mock<IEntityRepository>();
                stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                    .Returns("Stub");
                const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
                var entity = new EntityClass(stubEntityRepository.Object);
                // Act 
                var name = entity.GetNameWithPrefix(12);
                // Assert
                Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
            }
        }
        public class EntityClass
        {
            private IEntityRepository _entityRepository;
            public EntityClass(IEntityRepository entityRepository)
            {
                this._entityRepository = entityRepository;
            }
            public string Name { get; set; }
            public string GetNameWithPrefix(int id)
            {
                string name = string.Empty;
                if (id > 0)
                {
                    name = this._entityRepository.GetName(id);
                }
                return "Mr. " + name;
            }
        }
        public interface IEntityRepository
        {
            string GetName(int id);
        }
        public class EntityRepository:IEntityRepository
        {
            public string GetName(int id)
            {
                // Code to connect to DB and get name based on Id
                return "NameFromDb";
            }
        }
    }
    
     public void Analyze(string filename)
            {
                if(filename.Length<8)
                {
                    try
                    {
                        errorService.LogError("long file entered named:" + filename);
                    }
                    catch (Exception e)
                    {
                        mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                    }
                }
            }
    
    class Foo(object):
        def bar1(self):
            pass
    
        def bar2(self):
            #or ...
            raise NotImplementedError
    
        def bar3(self):
            #or return dummy data
            return "Dummy Data"
    
    import os
    import os.path
    
    def rm(filename):
        if os.path.isfile(filename):
            os.remove(filename)
    
    from mymodule import rm
    import mock
    import unittest
    
    class RmTestCase(unittest.TestCase):
        @mock.patch('mymodule.os')
        def test_rm(self, mock_os):
            rm("any path")
            # test that rm called os.remove with the right parameters
            mock_os.remove.assert_called_with("any path")
    
    if __name__ == '__main__':
        unittest.main()
    
    var Stub = {
       method_a: function(param_a, param_b){
          return 'This is an static result';
       }
    }
    
    var Mock = {
       calls: {
          method_a: 0
       }
    
       method_a: function(param_a, param_b){
         this.method_a++; 
         console.log('Mock.method_a its been called!');
       }
    }
    
    @Mock Foo fooMock
    
    when(fooMock.hello()).thenReturn("hello you!");
    
    verify(fooMock).hello()
    
    public class HelloStub extends Hello{    
      public String hello { 
          return "hello you!"; 
      }
    }
    
    public class HelloStub extends Hello{    
      public HelloStub(String helloReturn){
           this.helloReturn = helloReturn;
      }
      public String hello { 
          return helloReturn; 
      }
    }