<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Database on WebDevStation</title>
    <link>https://webdevstation.com/tags/database/</link>
    <description>1 article tagged Database — tutorials, code examples and notes from building real systems, newest first.</description>
    <generator>Hugo</generator>
    <language>en</language>
    <managingEditor>Alex</managingEditor>
    <webMaster>Alex</webMaster>
    <copyright>© 2026 WebDevStation</copyright>
    <lastBuildDate>Tue, 22 Dec 2020 20:12:51 +0000</lastBuildDate>
    <atom:link href="https://webdevstation.com/tags/database/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to test database interactions in golang applications</title>
      <link>https://webdevstation.com/posts/how-to-test-database-interactions-go/</link>
      <pubDate>Tue, 22 Dec 2020 20:12:51 +0000</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/how-to-test-database-interactions-go/</guid>
      <description>Testing of functions with database interactions always was challenging. Recently, I found a wonderful library, which will simplify writing tests and mocking database…</description>
      <content:encoded><![CDATA[<p>Testing of functions with database interactions always was challenging. Recently, I found a wonderful library <a href="https://github.com/DATA-DOG/go-sqlmock">go-sqlmock</a> which will simplify writing tests and mocking database queries in golang applications a lot.</p>
<p>And I want to share a short example of how to work with it.</p>
<p>First, we have to install it</p>
<p><code>go get github.com/DATA-DOG/go-sqlmock</code></p>
<p>We have this function with SQL query:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">MenuByNameAndLanguage</span>(<span style="color:#a6e22e">ctx</span> <span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">Context</span>, <span style="color:#a6e22e">db</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">sql</span>.<span style="color:#a6e22e">DB</span>, <span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">langcode</span> <span style="color:#66d9ef">string</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">Menu</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">result</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Query</span>(<span style="color:#e6db74">&#34;SELECT id, langcode, title, link__uri, view_sidemenu FROM menu_link_content_data WHERE menu_name=? AND langcode=?&#34;</span>,
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">name</span>,
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">langcode</span>,
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">Close</span>()
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">menuLinks</span> []<span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">MenuLink</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">Next</span>() {
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">menuLink</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">MenuLink</span>{}
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">Scan</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">menuLink</span>.<span style="color:#a6e22e">ID</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">menuLink</span>.<span style="color:#a6e22e">Langcode</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">menuLink</span>.<span style="color:#a6e22e">Title</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">menuLink</span>.<span style="color:#a6e22e">URL</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">menuLink</span>.<span style="color:#a6e22e">SideMenu</span>)
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">menuLinks</span> = append(<span style="color:#a6e22e">menuLinks</span>, <span style="color:#a6e22e">menuLink</span>)    
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menu</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">Menu</span>{
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">Name</span>: <span style="color:#a6e22e">name</span>,
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">Links</span>: <span style="color:#a6e22e">menuLinks</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">menu</span>, <span style="color:#a6e22e">err</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This function just getting menu links by menu name and language.</p>
<p>And now let&rsquo;s test it.</p>
<p>We are going to test that MenuByNameAndLanguage function will return correct Menu structure.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">menu</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;context&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;testing&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;github.com/DATA-DOG/go-sqlmock&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;github.com/stretchr/testify/assert&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;gitlab.mfb.io/user/graphql_server/models&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestShouldReturnCorrectMenu</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Creates sqlmock database connection and a mock to manage expectations.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">db</span>, <span style="color:#a6e22e">mock</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">sqlmock</span>.<span style="color:#a6e22e">New</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatalf</span>(<span style="color:#e6db74">&#34;an error &#39;%s&#39; was not expected when opening a stub database connection&#34;</span>, <span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Closes the database and prevents new queries from starting.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Close</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Here we are creating rows in our mocked database.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">rows</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">sqlmock</span>.<span style="color:#a6e22e">NewRows</span>([]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;id&#34;</span>, <span style="color:#e6db74">&#34;langcode&#34;</span>, <span style="color:#e6db74">&#34;title&#34;</span>, <span style="color:#e6db74">&#34;link__uri&#34;</span>, <span style="color:#e6db74">&#34;view_sidemenu&#34;</span>}).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">AddRow</span>(<span style="color:#ae81ff">1</span>, <span style="color:#e6db74">&#34;en&#34;</span>, <span style="color:#e6db74">&#34;enTitle&#34;</span>, <span style="color:#e6db74">&#34;/en-link&#34;</span>, <span style="color:#e6db74">&#34;0&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">AddRow</span>(<span style="color:#ae81ff">2</span>, <span style="color:#e6db74">&#34;en&#34;</span>, <span style="color:#e6db74">&#34;enTitle2&#34;</span>, <span style="color:#e6db74">&#34;/en-link2&#34;</span>, <span style="color:#e6db74">&#34;0&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// This is most important part in our test. Here, literally, we are altering SQL query from MenuByNameAndLanguage</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">﻿</span>    <span style="color:#75715e">// function and replacing result with our expected result. </span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">mock</span>.<span style="color:#a6e22e">ExpectQuery</span>(<span style="color:#e6db74">&#34;^SELECT (.+) FROM menu_link_content_data*&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithArgs</span>(<span style="color:#e6db74">&#34;main&#34;</span>, <span style="color:#e6db74">&#34;en&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WillReturnRows</span>(<span style="color:#a6e22e">rows</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">ctx</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">context</span>.<span style="color:#a6e22e">TODO</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Calls MenuByNameAndLanguage with mocked database connection in arguments list. </span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menu</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">MenuByNameAndLanguage</span>(<span style="color:#a6e22e">ctx</span>, <span style="color:#a6e22e">db</span>, <span style="color:#e6db74">&#34;main&#34;</span>, <span style="color:#e6db74">&#34;en&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Here we just construction our expecting result.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">menuLinks</span> []<span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">MenuLink</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menuLink1</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">MenuLink</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">ID</span>:       <span style="color:#ae81ff">1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Title</span>:    <span style="color:#e6db74">&#34;enTitle&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Langcode</span>: <span style="color:#e6db74">&#34;en&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">URL</span>:      <span style="color:#e6db74">&#34;/en-link&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">SideMenu</span>: <span style="color:#e6db74">&#34;0&#34;</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menuLinks</span> = append(<span style="color:#a6e22e">menuLinks</span>, <span style="color:#a6e22e">menuLink1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menuLink2</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">MenuLink</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">ID</span>:       <span style="color:#ae81ff">2</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Title</span>:    <span style="color:#e6db74">&#34;enTitle2&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Langcode</span>: <span style="color:#e6db74">&#34;en&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">URL</span>:      <span style="color:#e6db74">&#34;/en-link2&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">SideMenu</span>: <span style="color:#e6db74">&#34;0&#34;</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">menuLinks</span> = append(<span style="color:#a6e22e">menuLinks</span>, <span style="color:#a6e22e">menuLink2</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">expectedMenu</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">Menu</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Name</span>:  <span style="color:#e6db74">&#34;main&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Links</span>: <span style="color:#a6e22e">menuLinks</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// And, finally, let&#39;s check if result from MenuByNameAndLanguage equal with expected result.// Here I used Testify library (https://github.com/stretchr/testify).</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">assert</span>.<span style="color:#a6e22e">Equal</span>(<span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">expectedMenu</span>, <span style="color:#a6e22e">menu</span>)
</span></span><span style="display:flex;"><span>} 
</span></span></code></pre></div><p>As you see everything in this example was pretty straightforward.</p>
<p>For mo details, you can refer to <a href="https://godoc.org/github.com/DATA-DOG/go-sqlmock">GoDocs</a>.</p>
<p>Mocking the database is also the easiest way to test your error paths: force <code>sql.ErrNoRows</code> and assert that your store turns it into a sentinel your handler can branch on. I covered how to build those sentinels in <a href="/posts/error-handling-in-go/">error handling in Go</a>. The same fake-the-boundary trick works for code that calls a language model, which people usually assume is untestable — <a href="/posts/testing-go-code-that-calls-an-llm/">how to test Go code that calls an LLM</a>.</p>]]></content:encoded>
      <category>Go Programming</category>
      <category>Backend Development</category>
      <category>Testing</category>
    </item>
  </channel>
</rss>
