4

我正在尝试遵循 TDD,但遇到了一个小问题。我写了一个测试来将一个新用户插入数据库。在 MyService 类上调用了插入新用户,因此我继续创建了 mytest。它失败了,我开始在 MyService 类上实现我的 CreateUser 方法。

我遇到的问题是 MyService 将调用存储库(另一个类)来进行数据库插入。

所以我想我会使用一个模拟框架来模拟这个 Repository 类,但这是正确的方法吗?

这意味着我必须更改我的测试以实际为我的用户存储库创建一个模拟。但这是推荐的吗?我最初编写了我的测试并使其失败,现在我意识到我需要一个存储库并且需要模拟它,所以我必须更改我的测试以适应模拟对象。有点臭?

我想在这里得到一些反馈。

如果这是要走的路,那么我什么时候会创建实际的用户存储库?这需要自己的测试吗?

还是我应该忘记嘲笑任何事情?但这将被归类为集成测试而不是单元测试,因为我会将 MyService 和 User Repository 作为一个单元一起测试。

我有点失落;我想以正确的方式开始。

4

4 回答 4

6

所以我想我会使用一个模拟框架来模拟这个 Repository 类,但这是正确的方法吗?

是的,这是一个完全正确的方法,因为你应该单独测试你的类。即通过模拟所有依赖项。否则,您无法判断您的类是否失败或它的某些依赖项。

我最初编写了我的测试并使其失败,现在我意识到我需要一个存储库并且需要模拟它,所以我必须更改我的测试以适应模拟对象。有点臭?

Extracting classes, reorganizing methods, etc is a refactoring. And tests are here to help you with refactoring, to remove fear of change. It's completely normal to change your tests if implementation changes. I believe you didn't think that you could create perfect code from your first try and never change it again?

If this is the way to go then when would I create the actual User Repository? Would this need its own test?

You will create a real repository in your application. And you can write tests for this repository (i.e. check if it correctly calls the underlying data access provider, which should be mocked). But such tests usually are very time-consuming and brittle. So, it's better to write some acceptance tests, which exercise the whole application with real repositories.

Or should I just forget about mocking anything?

Just the opposite - you should use mocks to test classes in isolation. If mocking requires lots of work (data access, ui) then don't mock such resources and use real objects in integration or acceptance tests.

于 2013-06-25T16:31:40.933 回答
1

你肯定会模拟出对数据库的依赖,然后在你的服务上断言,在你的模拟上调用预期的方法。我赞扬您尝试遵循最佳实践,并鼓励您继续走这条路。正如您现在已经意识到的那样,随着您的前进,您将开始向您编写的类添加新的依赖项。我强烈建议您在外部满足这些依赖关系,例如创建一个接口 IUserRepository,这样您就可以模拟它,并将 IUserRepository 传递给您的服务的构造函数。然后您将其存储在一个实例变量中并调用您需要的方法(即_userRepository.StoreUser(user))。这样做的好处是,很容易从您的测试类中满足这些依赖关系,并且您可以担心对象的实例化,

tl;博士:创建一个模拟!

于 2013-06-25T16:26:45.930 回答
1

I have two set of testing libraries. One for UnitTests where I mock stuff. I only test units there. So if I would have a method of AddUser in the service I would create all the mocks I need to be able to test the code in that specific method. This gives me a possibility to test some code paths that I would not be able to verify otherwise.

Another test library is for Integration tests or functional tests or whatever you want to call it. This one is making sure that a specific use case. E.g. Creating a tag from the webpage will do what i expect it to do. For this I use the sql server that shipps with Visual studio 2012 and after every test I delete the database and start over.

In my case I would say that the integration tests are much more important then the unit tests. This is because my application does not have so much logic, instead it is displaying data from the database in different ways.

于 2013-06-25T17:56:44.243 回答
0

Your initial test was incomplete, that's all. The final test is always going to have to deal with the fact the new user gets persisted.

TDD does not prescribe the kind of test you should create. You have to choose beforehand if it's going to be a unit test or some kind of integration test. If it's a unit test, then the use of mocking is practically inevitable (except when the tested unit has no dependencies to isolate from). If it's an integration test, then actual database access (in this case) would have to be taken into account in the test.

Either kind of test is correct. Common wisdom is that a larger unit test suite is created, testing units in isolation, while a separate but smaller test suite exercises whole use case scenarios.

于 2013-06-27T13:05:51.750 回答