为什么我们需要模拟框架?

时间:2022-10-06 10:27:56

I have worked with code which had NUnit test written. But, I have never worked with mocking frameworks. What are they? I understand dependency injection and how it helps to improve the testability. I mean all dependencies can be mocked while unit testing. But, then why do we need mocking frameworks? Can't we simply create mock objects and provide dependencies. Am I missing something here? Thanks.

我使用过编写过NUnit测试的代码。但是,我从未使用过模拟框架。他们是什么?我理解依赖注入以及它如何帮助提高可测试性。我的意思是所有依赖项都可以在单元测试时进行模拟。但是,为什么我们需要模拟框架呢?我们不能简单地创建模拟对象并提供依赖关系。我在这里错过了什么吗?谢谢。

11 个解决方案

#1


12  

  • It makes mocking easier
  • 它使模拟更容易
  • They usually allow you to express testable assertions that refer to the interaction between objects.
  • 它们通常允许您表达可测试的断言,这些断言引用对象之间的交互。

Here you have an example:

这里有一个例子:

var extension = MockRepository
    .GenerateMock<IContextExtension<StandardContext>>();
  var ctx = new StandardContext();
  ctx.AddExtension(extension);
  extension.AssertWasCalled(
    e=>e.Attach(null), 
    o=>o.Constraints(Is.Equal(ctx)));

You can see that I explicitly test that the Attach method of the IContextExtension was called and that the input parameter was said context object. It would make my test fail if that did not happen.

您可以看到我明确地测试了IContextExtension的Attach方法被调用,并且输入参数是所述上下文对象。如果没有发生,它会使我的测试失败。

#2


11  

You can create mock objects by hand and use them during testing using Dependency Injection frameworks...but letting a mocking framework generate your mock objects for you saves time.

您可以手动创建模拟对象,并在使用依赖注入框架进行测试期间使用它们......但是让模拟框架为您生成模拟对象可以节省时间。

As always, if using the framework adds too much complexity to be useful then don't use it.

与往常一样,如果使用框架增加了太多的复杂性,那么就不要使用它。

#3


7  

Sometimes when working with third-party libraries, or even working with some aspects of the .NET framework, it is extremely difficult to write tests for some situations - for example, an HttpContext, or a Sharepoint object. Creating mock objects for those can become very cumbersome, so mocking frameworks take care of the basics so we can spend our time focusing on what makes our applications unique.

有时,在使用第三方库,甚至使用.NET框架的某些方面时,在某些情况下编写测试非常困难 - 例如,HttpContext或Sharepoint对象。为那些创建模拟对象会变得非常麻烦,因此模拟框架会处理基础知识,因此我们可以将时间花在专注于使应用程序独特的内容上。

#4


3  

Using a mocking framework can be a much more lightweight and simple solution to provide mocks than actually creating a mock object for every object you want to mock.

使用模拟框架可以提供模拟的轻量级和简单的解决方案,而不是为要模拟的每个对象实际创建模拟对象。

For example, mocking frameworks are especially useful to do things like verify that a call was made (or even how many times that call was made). Making your own mock objects to check behaviors like this (while mocking behavior is a topic in itself) is tedious, and yet another place for you to introduce a bug.

例如,模拟框架对于执行诸如验证调用(甚至调用的次数)之类的操作特别有用。制作自己的模拟对象来检查这样的行为(虽然模拟行为本身就是一个主题)是单调乏味的,而且是另一个引入错误的地方。

Check out Rhino Mocks for an example of how powerful a mocking framework can be.

查看Rhino Mocks,了解一个模拟框架有多强大的例子。

#5


3  

Mock objects take the place of any large/complex/external objects your code needs access to in order to run.

模拟对象取代了代码需要访问的任何大型/复杂/外部对象才能运行。

They are beneficial for a few reasons:

它们有益于以下几个原因:

  • Your tests are meant to run fast and easily. If your code depends on, say, a database connection then you would need to have a fully configured and populated database running in order to run your tests. This can get annoying, so you create a replace - a "mock" - of the database connection object that just simulates the database.

    您的测试旨在快速轻松地运行。如果您的代码依赖于数据库连接,那么您需要运行完全配置和填充的数据库才能运行测试。这可能会很烦人,所以你创建了一个替换 - 一个“模拟” - 只是模拟数据库的数据库连接对象。

  • You can control exactly what output comes out of the Mock objects and can therefore use them as controllable data sources to your tests.

    您可以精确控制Mock对象的输出,因此可以将它们用作测试的可控数据源。

  • You can create the mock before you create the real object in order to refine its interface. This is useful in Test-driven Development.

    您可以在创建真实对象之前创建模拟以优化其界面。这在测试驱动开发中很有用。

#6


2  

The only reason to use a mocking library is that it makes mocking easier.

使用模拟库的唯一原因是它使模拟更容易。

Sure, you can do it all without the library, and that is fine if it's simple, but as soon as they start getting complicated, libraries are much easier.

当然,你可以在没有库的情况下完成所有这一切,如果它很简单就可以了,但是一旦它们开始变得复杂,库就会容易得多。

Think of this in terms of sorting algorithms, sure anyone can write one, but why? If the code already exists and is simple to call... why not use it?

从排序算法的角度考虑这一点,确定任何人都可以写一个,但为什么呢?如果代码已经存在并且很容易调用...为什么不使用它?

#7


1  

You certainly can mock your dependencies manually, but with a framework it takes a lot of the tedious work away. Also the assertions usually available make it worth it to learn.

你当然可以手动模拟你的依赖项,但是使用框架需要花费大量繁琐的工作。通常可用的断言使它值得学习。

#8


1  

Mocking frameworks allow you to isolate units of code that you wish to test from that code's dependencies. They also allow you to simulate various behaviors of your code's dependencies in a test environment that might be difficult to setup or reproduce otherwise.

模拟框架允许您从该代码的依赖项中隔离您希望测试的代码单元。它们还允许您在测试环境中模拟代码依赖关系的各种行为,否则可能难以设置或重现。

For example if I have a class A containing business rules and logic that I wish to test, but this class A depends on a data-access classes, other business classes, even u/i classes, etc., these other classes can be mocked to perform in a certain manner (or in no manner at all in the case of loose mock behavior) to test the logic within your class A based on every imaginable way that these other classes could conceivably behave in a production environment.

例如,如果我有一个包含我希望测试的业务规则和逻辑的A类,但是这个A类依赖于数据访问类,其他业务类,甚至是u / i类等,这些其他类可以被模拟以某种方式执行(或者在松散的模拟行为的情况下根本不执行),以基于这些其他类可以想象在生产环境中行为的可想象的方式来测试类A中的逻辑。

To give a deeper example, suppose that your class A invokes a method on a data access class such as

为了给出更深层次的示例,假设您的类A在数据访问类上调用方法,例如

public bool IsOrderOnHold(int orderNumber) {}

then a mock of that data access class could be setup to return true every time or to return false every time, to test how your class A responds to such circumstances.

然后可以将该数据访问类的模拟设置为每次返回true或每次都返回false,以测试A类如何响应这种情况。

#9


1  

I'd claim you don't. Writing test doubles isn't a large chore in 9 times out of 10. Most of the time it's done almost entirely automatically by just asking resharper to implement an interface for you and then you just add the minor detail needed for this double (because you aren't doing a bunch of logic and creating these intricate super test doubles, right? Right?)

我声称你没有。编写测试双打并不是10次中的9次。在大多数情况下,只需要让resharper为您实现一个接口,然后您只需添加此双精度所需的次要细节(因为您没有做一堆逻辑并创建这些错综复杂的超级测试双打,对吧?对吗?)

"But why would I want my test project bloated with a bunch of test doubles" you may ask. Well you shouldn't. the DRY principle holds for tests as well. Create GOOD test doubles that are reusable and have descriptive names. This makes your tests more readable too.

你可能会问,“但为什么我希望我的测试项目充满了一堆测试双打”。那么你不应该。 DRY原则也适用于测试。创建可重复使用且具有描述性名称的GOOD测试双精度数。这使您的测试更具可读性。

One thing it DOES make harder is to over-use test doubles. I tend to agree with Roy Osherove and Uncle Bob, you really don't want to create a mock object with some special configuration all that often. This is in itself a design smell. Using a framework it's soooo easy to just use test doubles with intricate logic in just about every test and in the end you find that you haven't really tested your production code, you have merely tested the god-awful frankenstein's monsteresque mess of mocks containing mocks containing more mocks. You'll never "accidentally" do this if you write your own doubles.

它更难做的一件事是过度使用测试双打。我倾向于同意Roy Osherove和Uncle Bob,你真的不想创建一个经常使用一些特殊配置的模拟对象。这本身就是一种设计气味。使用一个框架就可以很容易地在几乎每个测试中使用复杂逻辑的测试双精度,最后你发现你没有真正测试过你的生产代码,你只是测试了那个令人难以置信的frankenstein的monsteresque混乱的模拟包含嘲笑包含更多的嘲笑。如果你写自己的双打,你永远不会“意外地”这样做。

Of course, someone will point out that there are times when you "have" to use a framework, not doing so would be plain stupid. Sure, there are cases like that. But you probably don't have that case. Most people don't, and only for a small part of the code, or the code itself is really bad.

当然,有人会指出,有时你“有”使用框架,不这样做是明显的愚蠢。当然,有类似的情况。但你可能没有那种情况。大多数人没有,只有一小部分代码,或者代码本身非常糟糕。

I'd recommend anyone (ESPECIALLY a beginner) to stay away from frameworks and learn how to get by without them, and then later when they feel that they really have to they can use whatever framework they think is the most suitable, but by then it'll be an informed desicion and they'll be far less likely to abuse the framework to create bad code.

我建议任何人(特别是初学者)远离框架并学习如何在没有框架的情况下顺利通过,然后当他们觉得他们真的需要时他们可以使用他们认为最合适的框架,但到那时这将是一个明智的决定,他们将不太可能滥用框架来创建错误的代码。

#10


0  

Well mocking frameworks make my life much easier and less tedious so I can spend time on actually writing code. Take for instance Mockito (in the Java world)

好的模拟框架使我的生活更轻松,更乏味,所以我可以花时间实际编写代码。以Mockito为例(在Java世界中)

 //mock creation
 List mockedList = mock(List.class);

 //using mock object
 mockedList.add("one");
 mockedList.clear();

 //verification
 verify(mockedList).add("one");
 verify(mockedList).clear();

 //stubbing using built-in anyInt() argument matcher
 when(mockedList.get(anyInt())).thenReturn("element");

 //stubbing using hamcrest (let's say isValid() returns your own hamcrest matcher):
 when(mockedList.contains(argThat(isValid()))).thenReturn("element");

 //following prints "element"
 System.out.println(mockedList.get(999));

Though this is a contrived example if you replace List.class with MyComplex.class then the value of having a mocking framework becomes evident. You could write your own or do without but why would you want to go that route.

虽然这是一个人为的例子,如果你用MyComplex.class替换List.class,那么拥有一个模拟框架的价值就变得明显了。你可以写自己的或不做,但为什么你想要走那条路。

#11


0  

I first grok'd why I needed a mocking framework when I compared writing test doubles by hand for a set of unit tests (each test needed slightly different behaviour so I was creating subclasses of a base fake type for each test) with using something like RhinoMocks or Moq to do the same work.

我首先想知道为什么我需要一个模拟框架,当我比较一组单元测试时手动编写测试双打(每个测试需要稍微不同的行为,所以我为每个测试创建一个基本假类型的子类)使用类似的东西RhinoMocks或Moq也做同样的工作。

Simply put it was much faster to use a framework to generate all of the fake objects I needed rather than writing (and debugging) my own fakes by hand.

简单地说,使用框架来生成我需要的所有假对象要快得多,而不是手工编写(和调试)我自己的假货。

#1


12  

  • It makes mocking easier
  • 它使模拟更容易
  • They usually allow you to express testable assertions that refer to the interaction between objects.
  • 它们通常允许您表达可测试的断言,这些断言引用对象之间的交互。

Here you have an example:

这里有一个例子:

var extension = MockRepository
    .GenerateMock<IContextExtension<StandardContext>>();
  var ctx = new StandardContext();
  ctx.AddExtension(extension);
  extension.AssertWasCalled(
    e=>e.Attach(null), 
    o=>o.Constraints(Is.Equal(ctx)));

You can see that I explicitly test that the Attach method of the IContextExtension was called and that the input parameter was said context object. It would make my test fail if that did not happen.

您可以看到我明确地测试了IContextExtension的Attach方法被调用,并且输入参数是所述上下文对象。如果没有发生,它会使我的测试失败。

#2


11  

You can create mock objects by hand and use them during testing using Dependency Injection frameworks...but letting a mocking framework generate your mock objects for you saves time.

您可以手动创建模拟对象,并在使用依赖注入框架进行测试期间使用它们......但是让模拟框架为您生成模拟对象可以节省时间。

As always, if using the framework adds too much complexity to be useful then don't use it.

与往常一样,如果使用框架增加了太多的复杂性,那么就不要使用它。

#3


7  

Sometimes when working with third-party libraries, or even working with some aspects of the .NET framework, it is extremely difficult to write tests for some situations - for example, an HttpContext, or a Sharepoint object. Creating mock objects for those can become very cumbersome, so mocking frameworks take care of the basics so we can spend our time focusing on what makes our applications unique.

有时,在使用第三方库,甚至使用.NET框架的某些方面时,在某些情况下编写测试非常困难 - 例如,HttpContext或Sharepoint对象。为那些创建模拟对象会变得非常麻烦,因此模拟框架会处理基础知识,因此我们可以将时间花在专注于使应用程序独特的内容上。

#4


3  

Using a mocking framework can be a much more lightweight and simple solution to provide mocks than actually creating a mock object for every object you want to mock.

使用模拟框架可以提供模拟的轻量级和简单的解决方案,而不是为要模拟的每个对象实际创建模拟对象。

For example, mocking frameworks are especially useful to do things like verify that a call was made (or even how many times that call was made). Making your own mock objects to check behaviors like this (while mocking behavior is a topic in itself) is tedious, and yet another place for you to introduce a bug.

例如,模拟框架对于执行诸如验证调用(甚至调用的次数)之类的操作特别有用。制作自己的模拟对象来检查这样的行为(虽然模拟行为本身就是一个主题)是单调乏味的,而且是另一个引入错误的地方。

Check out Rhino Mocks for an example of how powerful a mocking framework can be.

查看Rhino Mocks,了解一个模拟框架有多强大的例子。

#5


3  

Mock objects take the place of any large/complex/external objects your code needs access to in order to run.

模拟对象取代了代码需要访问的任何大型/复杂/外部对象才能运行。

They are beneficial for a few reasons:

它们有益于以下几个原因:

  • Your tests are meant to run fast and easily. If your code depends on, say, a database connection then you would need to have a fully configured and populated database running in order to run your tests. This can get annoying, so you create a replace - a "mock" - of the database connection object that just simulates the database.

    您的测试旨在快速轻松地运行。如果您的代码依赖于数据库连接,那么您需要运行完全配置和填充的数据库才能运行测试。这可能会很烦人,所以你创建了一个替换 - 一个“模拟” - 只是模拟数据库的数据库连接对象。

  • You can control exactly what output comes out of the Mock objects and can therefore use them as controllable data sources to your tests.

    您可以精确控制Mock对象的输出,因此可以将它们用作测试的可控数据源。

  • You can create the mock before you create the real object in order to refine its interface. This is useful in Test-driven Development.

    您可以在创建真实对象之前创建模拟以优化其界面。这在测试驱动开发中很有用。

#6


2  

The only reason to use a mocking library is that it makes mocking easier.

使用模拟库的唯一原因是它使模拟更容易。

Sure, you can do it all without the library, and that is fine if it's simple, but as soon as they start getting complicated, libraries are much easier.

当然,你可以在没有库的情况下完成所有这一切,如果它很简单就可以了,但是一旦它们开始变得复杂,库就会容易得多。

Think of this in terms of sorting algorithms, sure anyone can write one, but why? If the code already exists and is simple to call... why not use it?

从排序算法的角度考虑这一点,确定任何人都可以写一个,但为什么呢?如果代码已经存在并且很容易调用...为什么不使用它?

#7


1  

You certainly can mock your dependencies manually, but with a framework it takes a lot of the tedious work away. Also the assertions usually available make it worth it to learn.

你当然可以手动模拟你的依赖项,但是使用框架需要花费大量繁琐的工作。通常可用的断言使它值得学习。

#8


1  

Mocking frameworks allow you to isolate units of code that you wish to test from that code's dependencies. They also allow you to simulate various behaviors of your code's dependencies in a test environment that might be difficult to setup or reproduce otherwise.

模拟框架允许您从该代码的依赖项中隔离您希望测试的代码单元。它们还允许您在测试环境中模拟代码依赖关系的各种行为,否则可能难以设置或重现。

For example if I have a class A containing business rules and logic that I wish to test, but this class A depends on a data-access classes, other business classes, even u/i classes, etc., these other classes can be mocked to perform in a certain manner (or in no manner at all in the case of loose mock behavior) to test the logic within your class A based on every imaginable way that these other classes could conceivably behave in a production environment.

例如,如果我有一个包含我希望测试的业务规则和逻辑的A类,但是这个A类依赖于数据访问类,其他业务类,甚至是u / i类等,这些其他类可以被模拟以某种方式执行(或者在松散的模拟行为的情况下根本不执行),以基于这些其他类可以想象在生产环境中行为的可想象的方式来测试类A中的逻辑。

To give a deeper example, suppose that your class A invokes a method on a data access class such as

为了给出更深层次的示例,假设您的类A在数据访问类上调用方法,例如

public bool IsOrderOnHold(int orderNumber) {}

then a mock of that data access class could be setup to return true every time or to return false every time, to test how your class A responds to such circumstances.

然后可以将该数据访问类的模拟设置为每次返回true或每次都返回false,以测试A类如何响应这种情况。

#9


1  

I'd claim you don't. Writing test doubles isn't a large chore in 9 times out of 10. Most of the time it's done almost entirely automatically by just asking resharper to implement an interface for you and then you just add the minor detail needed for this double (because you aren't doing a bunch of logic and creating these intricate super test doubles, right? Right?)

我声称你没有。编写测试双打并不是10次中的9次。在大多数情况下,只需要让resharper为您实现一个接口,然后您只需添加此双精度所需的次要细节(因为您没有做一堆逻辑并创建这些错综复杂的超级测试双打,对吧?对吗?)

"But why would I want my test project bloated with a bunch of test doubles" you may ask. Well you shouldn't. the DRY principle holds for tests as well. Create GOOD test doubles that are reusable and have descriptive names. This makes your tests more readable too.

你可能会问,“但为什么我希望我的测试项目充满了一堆测试双打”。那么你不应该。 DRY原则也适用于测试。创建可重复使用且具有描述性名称的GOOD测试双精度数。这使您的测试更具可读性。

One thing it DOES make harder is to over-use test doubles. I tend to agree with Roy Osherove and Uncle Bob, you really don't want to create a mock object with some special configuration all that often. This is in itself a design smell. Using a framework it's soooo easy to just use test doubles with intricate logic in just about every test and in the end you find that you haven't really tested your production code, you have merely tested the god-awful frankenstein's monsteresque mess of mocks containing mocks containing more mocks. You'll never "accidentally" do this if you write your own doubles.

它更难做的一件事是过度使用测试双打。我倾向于同意Roy Osherove和Uncle Bob,你真的不想创建一个经常使用一些特殊配置的模拟对象。这本身就是一种设计气味。使用一个框架就可以很容易地在几乎每个测试中使用复杂逻辑的测试双精度,最后你发现你没有真正测试过你的生产代码,你只是测试了那个令人难以置信的frankenstein的monsteresque混乱的模拟包含嘲笑包含更多的嘲笑。如果你写自己的双打,你永远不会“意外地”这样做。

Of course, someone will point out that there are times when you "have" to use a framework, not doing so would be plain stupid. Sure, there are cases like that. But you probably don't have that case. Most people don't, and only for a small part of the code, or the code itself is really bad.

当然,有人会指出,有时你“有”使用框架,不这样做是明显的愚蠢。当然,有类似的情况。但你可能没有那种情况。大多数人没有,只有一小部分代码,或者代码本身非常糟糕。

I'd recommend anyone (ESPECIALLY a beginner) to stay away from frameworks and learn how to get by without them, and then later when they feel that they really have to they can use whatever framework they think is the most suitable, but by then it'll be an informed desicion and they'll be far less likely to abuse the framework to create bad code.

我建议任何人(特别是初学者)远离框架并学习如何在没有框架的情况下顺利通过,然后当他们觉得他们真的需要时他们可以使用他们认为最合适的框架,但到那时这将是一个明智的决定,他们将不太可能滥用框架来创建错误的代码。

#10


0  

Well mocking frameworks make my life much easier and less tedious so I can spend time on actually writing code. Take for instance Mockito (in the Java world)

好的模拟框架使我的生活更轻松,更乏味,所以我可以花时间实际编写代码。以Mockito为例(在Java世界中)

 //mock creation
 List mockedList = mock(List.class);

 //using mock object
 mockedList.add("one");
 mockedList.clear();

 //verification
 verify(mockedList).add("one");
 verify(mockedList).clear();

 //stubbing using built-in anyInt() argument matcher
 when(mockedList.get(anyInt())).thenReturn("element");

 //stubbing using hamcrest (let's say isValid() returns your own hamcrest matcher):
 when(mockedList.contains(argThat(isValid()))).thenReturn("element");

 //following prints "element"
 System.out.println(mockedList.get(999));

Though this is a contrived example if you replace List.class with MyComplex.class then the value of having a mocking framework becomes evident. You could write your own or do without but why would you want to go that route.

虽然这是一个人为的例子,如果你用MyComplex.class替换List.class,那么拥有一个模拟框架的价值就变得明显了。你可以写自己的或不做,但为什么你想要走那条路。

#11


0  

I first grok'd why I needed a mocking framework when I compared writing test doubles by hand for a set of unit tests (each test needed slightly different behaviour so I was creating subclasses of a base fake type for each test) with using something like RhinoMocks or Moq to do the same work.

我首先想知道为什么我需要一个模拟框架,当我比较一组单元测试时手动编写测试双打(每个测试需要稍微不同的行为,所以我为每个测试创建一个基本假类型的子类)使用类似的东西RhinoMocks或Moq也做同样的工作。

Simply put it was much faster to use a framework to generate all of the fake objects I needed rather than writing (and debugging) my own fakes by hand.

简单地说,使用框架来生成我需要的所有假对象要快得多,而不是手工编写(和调试)我自己的假货。