{"id":241,"date":"2024-09-07T23:39:01","date_gmt":"2024-09-08T02:39:01","guid":{"rendered":"https:\/\/eliasdc.dev\/?p=241"},"modified":"2024-09-08T09:36:59","modified_gmt":"2024-09-08T12:36:59","slug":"want-better-unit-tests-with-in-memory-databases","status":"publish","type":"post","link":"https:\/\/eliasdc.dev\/index.php\/2024\/09\/07\/241\/","title":{"rendered":"Want Better Unit Tests with In-Memory Databases?"},"content":{"rendered":"\n<p>Developing .NET applications that interact with relational databases requires robust unit tests. While mocking is a common approach, it may not always accurately represent real-world database behavior. Using in-memory databases like SQLite for these tests offers several advantages:<\/p>\n\n\n\n<ul>\n<li><strong>Realism:<\/strong> By using an in-memory relational database, the test environment more closely resembles a production environment, allowing for more realistic testing of database interactions.<\/li>\n\n\n\n<li><strong>Isolation:<\/strong> Each test has its own isolated database, eliminating dependencies on external environments.<\/li>\n\n\n\n<li><strong>Cost:<\/strong> Eliminates the need for commercial database licenses.<\/li>\n\n\n\n<li><strong>Simplicity:<\/strong> Easier to set up compared to a full-fledged database.<\/li>\n\n\n\n<li><strong>Concurrency:<\/strong> Multiple developers can execute tests simultaneously without conflicts due to the isolation of each test.<\/li>\n<\/ul>\n\n\n\n<p>It&#8217;s important to note that unit tests with in-memory databases do not replace integration tests but complement your testing strategy. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"360\" height=\"201\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/hmmm.gif\" alt=\"\" class=\"wp-image-286\"\/><\/figure>\n\n\n\n<p><br>In this article, we&#8217;ll explore:<\/p>\n\n\n\n<ul>\n<li><strong>SQLite Challenges:<\/strong> Let&#8217;s use in-memory SQLite and highlight its limitations compared to a full relational DBMS.<\/li>\n\n\n\n<li><strong>Best practices:<\/strong> How to write effective unit tests with in-memory databases and how to combine them with mocking to simulate external dependencies.<\/li>\n\n\n\n<li><strong>Practical example:<\/strong> A .NET API with adaptable configuration, using SQLite for testing and a relational database (SQL Server) in a production environment.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>SQLite Challenges:<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"659\" height=\"430\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Challange.gif\" alt=\"\" class=\"wp-image-284\" style=\"width:401px;height:auto\"\/><\/figure>\n\n\n\n<p><br>SQLite is a lightweight and fast database, but it has its limitations.<\/p>\n\n\n\n<ul>\n<li><strong>Data Types:<\/strong> It doesn&#8217;t support all data types found in larger databases. For example, JSON can be problematic.<\/li>\n\n\n\n<li><strong>Advanced Features:<\/strong> It lacks features like partitioning, complex indexes, and distributed transactions, which are essential for more complex applications.<\/li>\n\n\n\n<li><strong>Scalability:<\/strong> It may struggle with large volumes of data and complex queries.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Best Practices <\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"727\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Go-horse-Process-1024x727.webp\" alt=\"\" class=\"wp-image-288\" style=\"width:459px;height:auto\" srcset=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Go-horse-Process-1024x727.webp 1024w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Go-horse-Process-300x213.webp 300w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Go-horse-Process-768x545.webp 768w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Go-horse-Process.webp 1186w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<ul>\n<li><strong>Tools and Frameworks:<\/strong> Use tools like Entity Framework Core or Dapper to simplify database configuration and interaction. In our example, we&#8217;re using Entity Framework Core, and when instantiating the context, we pass an option specifying where it should point (to the in-memory database or an external database). See the context class for an example of SQLite in-memory and SQL Server:<\/li>\n<\/ul>\n\n\n\n<p><strong>Context class:<\/strong><br>(used in all examples and in the API that will be made available in this post)<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"using System;\nusing System.Collections.Generic;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace DBRepository.Model;\n\npublic partial class EliasdcDevContext : DbContext\n{\n    public EliasdcDevContext(DbContextOptions&lt;EliasdcDevContext&gt; options)\n        : base(options)\n    {\n    }\n\n    public virtual DbSet&lt;Car&gt; Car { get; set; }\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        OnModelCreatingPartial(modelBuilder);\n    }\n\n    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);\n}\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Collections<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Generic<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Microsoft<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">EntityFrameworkCore<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">namespace<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Model<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">partial<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\"> : <\/span><span style=\"color: #4EC9B0\">DbContext<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">DbContextOptions<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        : <\/span><span style=\"color: #569CD6\">base<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">virtual<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DbSet<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #569CD6\">get<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #569CD6\">set<\/span><span style=\"color: #D4D4D4\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">protected<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">override<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">OnModelCreating<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">ModelBuilder<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">modelBuilder<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">OnModelCreatingPartial<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">modelBuilder<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">partial<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">OnModelCreatingPartial<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">ModelBuilder<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">modelBuilder<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Sql Server Example:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"public EliasdcDevContext Context { get; private set; }\n\n public Method()\n {\n     DbContextOptions&lt;EliasdcDevContext&gt; options = new DbContextOptionsBuilder&lt;EliasdcDevContext&gt;()         \n         .UseSqlServer(&quot;Server=xxx;initial catalog=xxx;persist security info=True;user id=xxx;password=xxx;MultipleActiveResultSets=True;Encrypt=False&quot;)\n         .Options;\n\n     Context = new EliasdcDevContext(options);            \n } \" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">get<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #4EC9B0\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">set<\/span><span style=\"color: #D4D4D4\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Method<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">     <\/span><span style=\"color: #4EC9B0\">DbContextOptions<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DbContextOptionsBuilder<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt;()         <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">         .<\/span><span style=\"color: #DCDCAA\">UseSqlServer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Server=xxx;initial catalog=xxx;persist security info=True;user id=xxx;password=xxx;MultipleActiveResultSets=True;Encrypt=False&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">         .<\/span><span style=\"color: #9CDCFE\">Options<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">     <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\">);            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> } <\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>SQLite In-memory:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"public EliasdcDevContext Context { get; private set; }\n\n public Method()\n {\n     DbContextOptions&lt;EliasdcDevContext&gt; options = new DbContextOptionsBuilder&lt;EliasdcDevContext&gt;()         \n         .UseSqlite(&quot;DataSource=:memory:&quot;)\n         .Options;\n\n     Context = new EliasdcDevContext(options);            \n } \" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">get<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #4EC9B0\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">set<\/span><span style=\"color: #D4D4D4\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Method<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">     <\/span><span style=\"color: #4EC9B0\">DbContextOptions<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DbContextOptionsBuilder<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt;()         <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">         .<\/span><span style=\"color: #DCDCAA\">UseSqlite<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;DataSource=:memory:&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">         .<\/span><span style=\"color: #9CDCFE\">Options<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">     <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\">);            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> } <\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In this way, it becomes easy to configure unit tests to point to an in-memory database, while your API, when running, points to another external database. Both use the same context class and its models.<\/p>\n\n\n\n<ul>\n<li><strong>Initialization and Destruction:<\/strong> Use a testing framework like xUnit or NUnit to create a fixture that initializes the database before each test and destroys it afterward. This ensures a clean environment for each test.<\/li>\n\n\n\n<li><strong>Specific Configurations:<\/strong> Define the cache size, enable or disable indexes, adjust page size, and other specific configurations for your database and tests.<\/li>\n<\/ul>\n\n\n\n<p>Example with xUnit:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"public class DatabaseFixture : IDisposable\n{\n    public EliasdcDevContext Context { get; private set; }\n\n    public DatabaseFixture()\n    {\n        DbContextOptions&lt;EliasdcDevContext&gt; options = new DbContextOptionsBuilder&lt;EliasdcDevContext&gt;()\n            \/*here you can put other definitions. \n             *Examples:\n             *  Cache=Shared: Allows the in-memory database to be shared across multiple connections.\n             *  Cache=Private: Creates a private in-memory database for each connection (default).\n             *  Foreign Keys=True: Enables foreign key constraint enforcement in SQLite.\n            *\/\n            .UseSqlite(&quot;DataSource=:memory:&quot;)\n            .Options;\n\n        Context = new EliasdcDevContext(options);            \n\n        Context.Database.OpenConnection();\n        Context.Database.EnsureCreated();\n    } \n\n    public void Dispose()\n    {\n        Context?.Dispose();\n    }\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\"> : <\/span><span style=\"color: #4EC9B0\">IDisposable<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #569CD6\">get<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">set<\/span><span style=\"color: #D4D4D4\">; }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #4EC9B0\">DbContextOptions<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DbContextOptionsBuilder<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/*here you can put other definitions. <\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">             *Examples:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">             *  Cache=Shared: Allows the in-memory database to be shared across multiple connections.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">             *  Cache=Private: Creates a private in-memory database for each connection (default).<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">             *  Foreign Keys=True: Enables foreign key constraint enforcement in SQLite.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #DCDCAA\">UseSqlite<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;DataSource=:memory:&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            .<\/span><span style=\"color: #9CDCFE\">Options<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">EliasdcDevContext<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">options<\/span><span style=\"color: #D4D4D4\">);            <\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Database<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">OpenConnection<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Database<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">EnsureCreated<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    } <\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Dispose<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">?.<\/span><span style=\"color: #DCDCAA\">Dispose<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<ul>\n<li><strong>Realistic Data: <\/strong>Generate data that represents real-world scenarios to ensure your tests are comprehensive.<\/li>\n\n\n\n<li><strong>Test Isolation:<\/strong> In-memory databases simplify test isolation because changes are discarded upon database restart. Nevertheless, in your testing framework, the database might not be restarted after each test. Therefore, it&#8217;s crucial to clean up the database either before or after each test to prevent test interference. The API we&#8217;ll make available will showcase both approaches. <\/li>\n\n\n\n<li><strong>Combination of in-memory database with mocks:<\/strong> For unit tests involving interactions with external systems or database features not available in SQLite, the combination of in-memory databases and mocks is essential to simulate these behaviors and ensure full code coverage.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Let&#8217;s Get Practical<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"263\" height=\"321\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Lets-Go-2.gif\" alt=\"\" class=\"wp-image-291\"\/><\/figure>\n\n\n\n<p><br>A sample API was created in .NET 8 using Entity Framework Core with SQL Server and xUnit with SQLite for unit tests. Along with the API on GitHub, I will include a script to create the table in the database and instructions on where to update the connection string (address, username, and password).<\/p>\n\n\n\n<p><strong>GitHub repository: <a href=\"https:\/\/github.com\/eliasedc\/MemoryDBToTest\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/eliasedc\/MemoryDBToTest<\/a><\/strong><\/p>\n\n\n\n<p>The API includes Swagger and has just one exposed method called <strong>GetCarByName<\/strong>, which essentially returns a list of cars stored in the database, with an option to filter by name.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">API Structure<\/h3>\n\n\n\n<p>The API is divided into five parts:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"350\" height=\"350\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/curious.gif\" alt=\"\" class=\"wp-image-292\"\/><\/figure>\n\n\n\n<p><br><\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-1 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<p><strong>1- Shared<\/strong>: Contains classes that can be used across all projects. In this case, it includes a DTO that reflects the <strong>Car <\/strong>table.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"281\" height=\"116\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-4.png\" alt=\"\" class=\"wp-image-254\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-2 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<p><br><strong>2- Api: <\/strong>Contains the API configurations and the exposed methods in the <strong>CarController.cs <\/strong>class.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"215\" height=\"225\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-5.png\" alt=\"\" class=\"wp-image-255\" style=\"width:193px;height:auto\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-3 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<p><br><strong>3- Domain: <\/strong>Contains the implementation of the exposed methods and is where business rules can be added.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"194\" height=\"154\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-6.png\" alt=\"\" class=\"wp-image-256\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-4 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<p><br><strong>4- Repository: <\/strong>Contains the models and the communication with the database.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"225\" height=\"212\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-7.png\" alt=\"\" class=\"wp-image-257\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-5 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<p><br><strong>5- Test: <\/strong>Contains the unit tests.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"241\" height=\"158\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-8.png\" alt=\"\" class=\"wp-image-258\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>When you run the API, Swagger will open automatically, and you can make requests by passing the name of a car to search for. You can use a single letter or a part of the car name. If you used my script, here is the list of cars available in the SQL Server database:<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-6 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<ul>\n<li>Chevrolet Silverado<\/li>\n\n\n\n<li>Toyota RAV4<\/li>\n\n\n\n<li>Tesla Model Y<\/li>\n\n\n\n<li>Honda CR-V<\/li>\n\n\n\n<li>Nissan Rogue<\/li>\n<\/ul>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<ul>\n<li>Ram Pickup<\/li>\n\n\n\n<li>Toyota Camry<\/li>\n\n\n\n<li>Jeep Grand Cherokee<\/li>\n\n\n\n<li>Toyota Highlander<\/li>\n<\/ul>\n<\/div>\n<\/div>\n\n\n\n<p>Example request using Swagger:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"453\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-9.png\" alt=\"\" class=\"wp-image-259\" srcset=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-9.png 910w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-9-300x149.png 300w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-9-768x382.png 768w\" sizes=\"(max-width: 910px) 100vw, 910px\" \/><\/figure>\n\n\n\n<p class=\"has-text-align-center\">&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"909\" height=\"857\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-10.png\" alt=\"\" class=\"wp-image-260\" srcset=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-10.png 909w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-10-300x283.png 300w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-10-768x724.png 768w\" sizes=\"(max-width: 909px) 100vw, 909px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><br>Initializing the Connection<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"370\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/Connection-Start.gif\" alt=\"\" class=\"wp-image-295\"\/><\/figure>\n\n\n\n<p><br>The context class was shown earlier in this post. Below is the location of the class in the project:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"227\" height=\"170\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-11.png\" alt=\"\" class=\"wp-image-261\"\/><\/figure>\n\n\n\n<p><br>The same context class, <strong>EliasdcDevContext.cs<\/strong>, and the model <strong>Car.cs<\/strong> are used for both SQL Server and SQLite in-memory connections.<\/p>\n\n\n\n<p><br>In the <strong>2-Api<\/strong> folder, within the <strong>Program.cs<\/strong> file, you can see how the context is configured for SQL Server:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"187\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12-1024x187.png\" alt=\"\" class=\"wp-image-262\" srcset=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12-1024x187.png 1024w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12-300x55.png 300w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12-768x140.png 768w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12-1140x208.png 1140w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-12.png 1142w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><br>In the <strong>5-Test<\/strong> folder, you can find the <strong>DatabaseFixture.cs<\/strong> class, which sets up the unit tests to use SQLite in-memory:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"293\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13-1024x293.png\" alt=\"\" class=\"wp-image-263\" srcset=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13-1024x293.png 1024w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13-300x86.png 300w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13-768x220.png 768w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13-1140x327.png 1140w, https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/image-13.png 1143w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>This demonstrates how simple it is to switch your code between different databases using the same context class.<\/p>\n\n\n\n<p><strong>Note<\/strong>: This example uses Entity Framework, but the same concept applies to projects that don&#8217;t use this structure and directly query the database. SQLite also allows running raw SQL queries (e.g., <em>INSERT<\/em>, <em>UPDATE<\/em>, <em>SELECT<\/em>, etc.).<\/p>\n\n\n\n<p><strong>Observation<\/strong>: SQLite does not support schemas, like in larger databases. Therefore, queries like <em>&#8220;SELECT * FROM schema.Cars&#8221;<\/em>  are not allowed. One workaround is to use an underscore to separate the schema and table names: <em>&#8220;SELECT * FROM schema_Cars&#8221;.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><br>Unit Tests<\/h3>\n\n\n\n<p>There are two unit test classes included in the API, with a subtle but important difference between them.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Class <code>UnitTest_IClassFixture<\/code><\/h4>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"using DBRepository.Model;\nusing Microsoft.EntityFrameworkCore;\nusing Shared;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Cars.Test\n{\n    public class UnitTest_IClassFixture : IClassFixture&lt;DatabaseFixture&gt;\n    {\n        private readonly DatabaseFixture _fixtureDB;\n        private Domain.Domain _domain;\n\n        public UnitTest_IClassFixture(DatabaseFixture fixture)\n        {\n            _fixtureDB = fixture;\n            _domain = new Domain.Domain(new DBRepository.DBRepository(_fixtureDB.Context));\n        }\n\n        [Theory]\n        [InlineData(&quot;Accord&quot;, 1)]\n        [InlineData(&quot;n&quot;, 2)]\n        public async Task ToMustReturnCarByName(string name, int count)\n        {\n            \/\/ Arrange\n            \/\/ This delete is necessary due to the IClassFixture implementation\n            _fixtureDB.Context.Database.ExecuteSqlRaw(&quot;DELETE FROM Car&quot;);\n\n            List&lt;Car&gt; cars = new List&lt;Car&gt;\n            {\n                new Car { Name = &quot;Honda Accord&quot;, CreatedDate = DateTime.Now },\n                new Car { Name = &quot;Subaru Outback&quot;, CreatedDate = DateTime.Now.AddDays(-1) },\n                new Car { Name = &quot;Ford Mustang&quot;, CreatedDate = DateTime.Now.AddDays(-2) }\n            };\n\n            _fixtureDB.Context.Car.AddRange(cars);\n            await _fixtureDB.Context.SaveChangesAsync();\n\n            \/\/ Act\n            List&lt;CarDTO&gt; result = await _domain.GetCarByName(name);\n\n            \/\/ Assert\n            Assert.NotNull(result);\n            Assert.Equal(count, result.Count);\n        }\n    }\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Model<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Microsoft<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">EntityFrameworkCore<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Shared<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Collections<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Generic<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Tasks<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Xunit<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">namespace<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Cars<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Test<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">UnitTest_IClassFixture<\/span><span style=\"color: #D4D4D4\"> : <\/span><span style=\"color: #4EC9B0\">IClassFixture<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">readonly<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">UnitTest_IClassFixture<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">fixture<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">fixture<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">Theory<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">InlineData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Accord&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">InlineData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;n&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Task<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">ToMustReturnCarByName<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">count<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Arrange<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ This delete is necessary due to the IClassFixture implementation<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Database<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">ExecuteSqlRaw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;DELETE FROM Car&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">cars<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Honda Accord&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Subaru Outback&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddDays<\/span><span style=\"color: #D4D4D4\">(-<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">) },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Ford Mustang&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddDays<\/span><span style=\"color: #D4D4D4\">(-<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">) }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            };<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Car<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddRange<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">cars<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">SaveChangesAsync<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Act<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">CarDTO<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetCarByName<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Assert<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">Assert<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">NotNull<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">Assert<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">count<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Count<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In this class, the <strong>IClassFixture <\/strong>implementation ensures that the <strong>DatabaseFixture <\/strong>constructor is called only once, regardless of the number of tests. At the end, the <strong>Dispose <\/strong>method is automatically called to release resources.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><br>Class <code>UnitTest_IDisposable<\/code><\/h4>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.125rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.125rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" data-code=\"using DBRepository.Model;\nusing Microsoft.EntityFrameworkCore;\nusing Shared;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Cars.Test\n{\n    public class UnitTest_IDisposable : IDisposable\n    {\n        private readonly DatabaseFixture _fixtureDB;\n        private Domain.Domain _domain;\n\n        public UnitTest_IDisposable()\n        {\n            _fixtureDB = new DatabaseFixture();\n            _domain = new Domain.Domain(new DBRepository.DBRepository(_fixtureDB.Context));\n        }\n\n        [Theory]\n        [InlineData(&quot;Accord&quot;, 1)]\n        [InlineData(&quot;n&quot;, 2)]\n        public async Task ToMustReturnCarByName(string name, int count)\n        {\n            \/\/ Arrange\n            List&lt;Car&gt; cars = new List&lt;Car&gt;\n            {\n                new Car { Name = &quot;Honda Accord&quot;, CreatedDate = DateTime.Now },\n                new Car { Name = &quot;Subaru Outback&quot;, CreatedDate = DateTime.Now.AddDays(-1) },\n                new Car { Name = &quot;Ford Mustang&quot;, CreatedDate = DateTime.Now.AddDays(-2) }\n            };\n\n            _fixtureDB.Context.Car.AddRange(cars);\n            await _fixtureDB.Context.SaveChangesAsync();\n\n            \/\/ Act\n            List&lt;CarDTO&gt; result = await _domain.GetCarByName(name);\n\n            \/\/ Assert\n            Assert.NotNull(result);\n            Assert.Equal(count, result.Count);\n        }\n\n        public void Dispose()\n        {\n            _fixtureDB.Dispose();\n        }\n    }\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Model<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Microsoft<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">EntityFrameworkCore<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Shared<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Collections<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Generic<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Tasks<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Xunit<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">namespace<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Cars<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Test<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">UnitTest_IDisposable<\/span><span style=\"color: #D4D4D4\"> : <\/span><span style=\"color: #4EC9B0\">IDisposable<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">readonly<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">private<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">UnitTest_IDisposable<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DatabaseFixture<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Domain<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">DBRepository<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">Theory<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">InlineData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Accord&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        [<\/span><span style=\"color: #4EC9B0\">InlineData<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;n&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Task<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">ToMustReturnCarByName<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">count<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Arrange<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">cars<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Honda Accord&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\"> },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Subaru Outback&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddDays<\/span><span style=\"color: #D4D4D4\">(-<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">) },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">Name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;Ford Mustang&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">CreatedDate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">DateTime<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Now<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddDays<\/span><span style=\"color: #D4D4D4\">(-<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">) }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            };<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Car<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">AddRange<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">cars<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Context<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">SaveChangesAsync<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Act<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #4EC9B0\">List<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">CarDTO<\/span><span style=\"color: #D4D4D4\">&gt; <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_domain<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetCarByName<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">            \/\/ Assert<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">Assert<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">NotNull<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">Assert<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">count<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Count<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Dispose<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">_fixtureDB<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Dispose<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In this class, the <strong>IDisposable <\/strong>interface is implemented to ensure the <strong>Dispose <\/strong>method is called after each test, cleaning up the in-memory database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Conclusion<\/h2>\n\n\n\n<p>In summary, this API demonstrates how to flexibly integrate different databases using Entity Framework to manage both SQL Server and in-memory SQLite for testing. Throughout this post, we covered the pros and cons of using an in-memory database for unit tests, emphasizing its simplicity and limitations. Additionally, we highlighted the importance of unit testing and how different approaches, such as using <mark style=\"background-color:#ededed\" class=\"has-inline-color\">IClassFixture<\/mark><mark style=\"background-color:#ffffff\" class=\"has-inline-color has-white-color\"> <\/mark>and <mark style=\"background-color:#ededed\" class=\"has-inline-color\">IDisposable<\/mark>, affect the test lifecycle.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br>That&#8217;s it<\/h2>\n\n\n\n<p>I hope this example has been helpful and serves as a foundation for your implementations.<\/p>\n\n\n\n<p>See you next time!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"356\" height=\"189\" src=\"https:\/\/eliasdc.dev\/wp-content\/uploads\/2024\/09\/happy.gif\" alt=\"\" class=\"wp-image-296\"\/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Developing .NET applications that interact with relational databases requires robust unit tests. While mocking is a common approach, it may not always accurately represent real-world database behavior. Using in-memory databases like SQLite for these tests offers several advantages: It&#8217;s important to note that unit tests with in-memory databases do not replace integration tests but complement [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":309,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[1],"tags":[29,23,10,19,34,31,32,26,25,30,20,27,28,33,17,24,18,21,22],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/posts\/241"}],"collection":[{"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/comments?post=241"}],"version-history":[{"count":42,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":307,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/posts\/241\/revisions\/307"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/media\/309"}],"wp:attachment":[{"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/media?parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/categories?post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eliasdc.dev\/index.php\/wp-json\/wp\/v2\/tags?post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}