Is there a good use case for Mocking a DB?

polaris · · 485 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Using an interface seems to be considered a best practice for passing Database configuration to handlers, especially since it helps with mocking test data: <a href="http://www.alexedwards.net/blog/organising-database-access#using-an-interface">http://www.alexedwards.net/blog/organising-database-access#using-an-interface</a></p> <p>But I&#39;m having trouble understanding why I&#39;d want to mock my DB. It seems like &#34;fake testing&#34; my database provides no testing value other than speeding up my tests. In that case, can&#39;t I just skip my integration tests with:</p> <pre><code>go test -run ... </code></pre> <p>Plus, there&#39;s the downside that my test coverage looks great, but my app could break in production if my SQL queries aren&#39;t accurate. So, wouldn&#39;t it be better to skip testing the SQL queries than to pretend like I tested them?</p> <p>Also, if you have a function that gets data from a DB and then processes/manipulates it, I&#39;d typically refactor it.</p> <p>Instead of:</p> <pre><code>func GetAndDoStuffWithBooks() { books, err := db.FindAllBooks() for _, b := range books { // do stuff with books } } </code></pre> <p>I&#39;d do:</p> <pre><code>// Great for integration testing func GetAndDoStuffWithBooks() { books, err := db.FindAllBooks() books.DoStuff() } // Great for unit testing func (books *[]Book) DoStuff() { for _, b := range books { // do stuff with books } } </code></pre> <p>That way, I can unit test the functions in my app that don&#39;t touch the DB and use integration testing for the functions that do.</p> <p>Am I missing something where it&#39;s actually helpful to mock a DB?</p> <hr/>**评论:**<br/><br/>lethalman: <pre><p>Run integration tests or continuous tests with a real db. Mocking it is senseless to me, never had a good use case for it.</p></pre>: <pre><p>[deleted]</p></pre>lethalman: <pre><p>Actually yes, to make sure the database was called or not, and to mock the result of the query. But never went down to validate the query itself. For that I prefer integration tests against a real db.</p></pre>edsonmedina: <pre><p>If the test talks to the database then it&#39;s an integration test, not a unit test. </p></pre>Redundancy_: <pre><p>I think it&#39;s important to draw a distinction between mocking your db, which is to provide a stand-in for how your DB works, and creating an interface, which is an abstraction that isolates the rest of your application from being coupled to a DB. Do abstract your data source, don&#39;t mock your DB.</p> <p>You&#39;re creating an interface that expresses intent, which means you know the boundary of the testing - if your application tests fail, the problem is in there. You can even write some slow tests that check that the db implementation works as intended, and know that you only need to run those when you change the details inside the box.</p> <p>Provisioning databases is slow, testing application logic against it is hard to set up and also slow. Testing with a real database can make your tests run so slowly that they aren&#39;t run and become useless. I think a project I looked at had a DB provisioning process in containers that took upwards of 5 minutes. Unit testing should be fast (sub-second), and it should be constrained to small volumes of code to better indicate where the issue is.</p></pre>ionrock: <pre><p>I think this is the best approach to take regarding testing with or w/o a real database. I&#39;d also point out that in your example, you don&#39;t verify the query you are passing to the database. There can be value in making assertions that you are getting the variables you expect and that they have been mutated accordingly before being passed to the query.</p> <p>This may not be necessary if you are using an ORM that generates your queries, but at the same, your ORM may require a mock database in order to work within the confines of a unit test (ie it&#39;s fast). </p> <p>All that said, if you use a lot of different services you will likely need to mock them in some shape or form that makes the local test incomplete. In order to gain confidence in what you release, spend the time to create ephemeral production like environments and integration tests that can run in that environment. If you can&#39;t do that, then that is where you can have a much bigger impact vs whether you mock or not. </p></pre>Redundancy_: <pre><p>It&#39;s also worth noting that you don&#39;t have to make one test implementation that does everything for every test, you can make a &#39;null&#39; implementation that satisfies the interfaces, and then implement only enough test stub to recreate the behaviour you need per test, which simplifies things considerably in some cases.</p> <p>If you find that you have to stub out a lot of calls to get something working for a single test, the surface area of your interaction may be too large.</p></pre>gopher1717: <pre><p>I personally recommend using a real database to run tests. <a href="https://github.com/go-testfixtures/test%20fixtures" rel="nofollow">This lib</a> may help you with that. Also take a look at the &#34;Alternatives&#34; section in the README.</p></pre>kardianos: <pre><p>I wouldn&#39;t mock your DB.</p> <p>If anything, learn to unit test your DB. Create scripts (or snapshot systems) that can populate a test DB (created when you start the unit test) and run it for realz. Or unit test your SQL outside of your application, or decide that your SQL doesn&#39;t really benefit your ROI to be unit tested.</p> <p>But yeah, don&#39;t mock it.</p> <p>I have setup test data to test the complex logic directly after a database call, but that&#39;s different.</p></pre>everdev: <pre><p>Cool -- I wonder why so many blogs recommend it</p></pre>connerp: <pre><p>A good use case might be if you were writing a db driver/adapter</p></pre>jaekim: <pre><p>To answer your title question, you may want to have more complex error handling logic than just returning the error. In that situation, mocking the db lets you test that logic.</p></pre>cflewis: <pre><p>I spawn an in-memory SQLite database and talk to that.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

485 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传