{"id":331,"date":"2020-07-12T10:42:31","date_gmt":"2020-07-12T05:12:31","guid":{"rendered":"https:\/\/saurabhjain1537.wordpress.com\/?p=331"},"modified":"2025-02-27T20:03:44","modified_gmt":"2025-02-27T14:33:44","slug":"in-memory-unit-test-for-net-entity-framework-application","status":"publish","type":"post","link":"https:\/\/saurabhjain.dev\/?p=331","title":{"rendered":"In-memory unit test for .Net Entity Framework Application"},"content":{"rendered":"\n<p class=\"has-medium-font-size\"><strong>Objective<\/strong><\/p>\n\n\n\n<p>Creating repeatable Unit Test cases for a .Net applications which uses Entity Framework Core for database operations.<\/p>\n\n\n\n<p>It is recommended to write independent and repeatable test cases for the business logic. We need to handle certain cases where logic depends upon the data already existing in database. In such scenarios we can use an in-memory database like SQLite.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Setup<\/strong><\/p>\n\n\n\n<p>Following tech stack is used in this example<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>.Net Core 3.1<\/li><li>NUnit 3.12<\/li><li>EntityFrameworkCore Sqlite 3.1.5<\/li><li>Visual Studio Code<\/li><\/ol>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Application<\/strong><\/p>\n\n\n\n<p>Let&#8217;s build a school management application which is going to check if there is vacancy for admission in a class.<\/p>\n\n\n\n<p>Create a new dotnet console application SchoolApp:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"429\" height=\"37\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-10.png?w=429\" alt=\"\" class=\"wp-image-350\" \/><\/figure>\n\n\n\n<p>Add Model classes for Student and Class information:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"453\" height=\"465\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-1.png?w=453\" alt=\"\" class=\"wp-image-335\" \/><figcaption>This class contains School-Class details including Max Number of Students allowed<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"447\" height=\"317\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-2.png?w=447\" alt=\"\" class=\"wp-image-336\" \/><figcaption>This class contains Student details<\/figcaption><\/figure>\n\n\n\n<p>These classes are associated with database tables and have Foreign Key relationship.<\/p>\n\n\n\n<p>Add AppDBContext extending EntityFrameworkCore DbContext.<\/p>\n\n\n\n<p>This class contains the DbSets for Model classes<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"541\" height=\"218\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-4.png?w=541\" alt=\"\" class=\"wp-image-340\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Override DBContextOptions constructor and OnConfiguring() so that the application uses in-memory SQLite for unit testing but a different Relational database like Oracle OR SQL Server during actual Production deployment<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"764\" height=\"360\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-5.png?w=764\" alt=\"\" class=\"wp-image-342\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Define Primary Key for each Model class<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"659\" height=\"306\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-6.png?w=659\" alt=\"\" class=\"wp-image-343\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Complete Class <a href=\"https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp\/Data\/AppDBContext.cs\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp\/Data\/AppDBContext.cs<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    public class AppDBContext:DbContext\n    {\n        public DbSet&lt;SchoolClass&gt; SchoolClasses { get; set;}\n        public DbSet&lt;Student&gt; Students {get; set;}\n\n        public AppDBContext() : base()\n        {\n        }\n\n        public AppDBContext(DbContextOptions&lt;AppDBContext&gt; options) : base(options)\n        {\n        }\n\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            if(!optionsBuilder.IsConfigured)\n            {\n                optionsBuilder.UseOracle(\"TODO - connection string\");\n            }\n        }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.Entity&lt;SchoolClass&gt;(s =&gt;\n                {\n                    s.HasKey(k =&gt; new {k.Id});\n                });\n\n            modelBuilder.Entity&lt;Student&gt;(s =&gt;\n                {\n                    s.HasKey(k =&gt; new {k.Id});\n                });\n        }\n\n    }<\/code><\/pre>\n\n\n\n<p>Add Admission class having appDBOptions variable.<\/p>\n\n\n\n<p>This class has a constructor to initialize DbContextOptions. The method getAppDBContext() is responsible for providing the appropriate DBContext considering if the application is actually deployed OR running unit tests.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"677\" height=\"606\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-7.png?w=677\" alt=\"\" class=\"wp-image-346\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Add a hasVacancy() method to determine if we can allow new admission in a particular school-class.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"990\" height=\"315\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-8.png?w=990\" alt=\"\" class=\"wp-image-347\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Complete Class <a href=\"https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp\/Admission.cs\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp\/Admission.cs<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    public class Admission\n    {\n        private DbContextOptions&lt;AppDBContext&gt; appDBOptions;\n\n        public Admission()\n        {\n            this.appDBOptions = null;\n        }\n\n        public Admission(DbContextOptions&lt;AppDBContext&gt; appDBOptions)\n        {\n            \/\/This constructor is used for Unit testing\n            this.appDBOptions = appDBOptions;\n        }\n\n        private AppDBContext getAppDBContext()\n        {\n            if(this.appDBOptions == null)\n            {\n                return new AppDBContext();\n            }\n            else\n            {\n                return new AppDBContext(this.appDBOptions);\n            }\n\n        }\n\n        public bool hasVacancy(string Standard)\n        {\n            bool hasVacancy = false;\n\n            using(var context = getAppDBContext())\n            {\n                hasVacancy = context.SchoolClasses\n                                        .Where( c =&gt; c.Standard == Standard &amp;&amp; c.MaxNumStudents &gt; c.Students.Count)\n                                        .Count()\n                              &gt; 0;\n\n            }\n\n            return hasVacancy;\n\n        }\n\n    }<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Test Project<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"455\" height=\"47\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-9.png?w=455\" alt=\"\" class=\"wp-image-349\" \/><figcaption>Create a new dotnet nunit application SchoolApp.Tests<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"719\" height=\"24\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-11.png?w=719\" alt=\"\" class=\"wp-image-352\" \/><figcaption>Add reference to SchoolApp project<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Add Test class AdmissionTest.<\/p>\n\n\n\n<p>This class uses in-memory SQLite to initialize an Object of Admission class.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1127\" height=\"347\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-12.png?w=1024\" alt=\"\" class=\"wp-image-354\" \/><\/figure>\n\n\n\n<p>SQLite connection<em> DataSource=:memory:<\/em> signifies in-memory usage<\/p>\n\n\n\n<p>Add a test case:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Inserts a new SchoolClass in database<\/li><li>Checks for Vacancy in the SchoolClass<\/li><li>Expects availability to be True<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"979\" height=\"389\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-13.png?w=979\" alt=\"\" class=\"wp-image-355\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Add a test case:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Inserts a new SchoolClass in database<\/li><li>Adds Max allowed number of students to the SchoolClass<\/li><li>Checks for Vacancy in the SchoolClass<\/li><li>Expects availability to be False<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"892\" height=\"505\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-14.png?w=892\" alt=\"\" class=\"wp-image-357\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Complete Test Class <a rel=\"noreferrer noopener\" href=\"https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp.Tests\/AdmissionTest.cs\" target=\"_blank\">https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/blob\/master\/SchoolApp.Tests\/AdmissionTest.cs<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    public class AdmissionTest\n    {\n        DbContextOptions&lt;AppDBContext&gt; configOptions = null;\n        private Admission admission;\n\n        &#091;SetUp]\n        public void Setup()\n        {\n            var connection = new SqliteConnection(\"DataSource=:memory:\");\n\n            configOptions = new DbContextOptionsBuilder&lt;AppDBContext&gt;().UseSqlite(connection).EnableSensitiveDataLogging().Options;\n\n            admission = new Admission(configOptions);\n\n        }\n\n        &#091;Test]\n        public void hasVacancy_True()\n        {\n            using (var context = new AppDBContext(configOptions))\n            {\n                context.Database.OpenConnection();\n                context.Database.EnsureCreated();\n\n                context.SchoolClasses.Add( new SchoolClass{ Id = 1, Standard = \"6\", Section = \"B\", MaxNumStudents = 10 });\n\n                context.SaveChanges();\n\n            }\n\n            var hasVacancy = admission.hasVacancy(\"6\");\n\n            Assert.AreEqual(true, hasVacancy);\n\n        }\n\n        &#091;Test]\n        public void hasVacancy_False()\n        {\n            using (var context = new AppDBContext(configOptions))\n            {\n                context.Database.OpenConnection();\n                context.Database.EnsureCreated();\n\n                var schoolClass6B = new SchoolClass{ Id = 1, Standard = \"6\", Section = \"B\", MaxNumStudents = 5 };\n                context.SchoolClasses.Add(schoolClass6B );\n                context.Students.Add( new Student { Id = 1, Name = \"a\", schoolClass = schoolClass6B});\n                context.Students.Add( new Student { Id = 2, Name = \"b\", schoolClass = schoolClass6B});\n                context.Students.Add( new Student { Id = 3, Name = \"c\", schoolClass = schoolClass6B});\n                context.Students.Add( new Student { Id = 4, Name = \"d\", schoolClass = schoolClass6B});\n                context.Students.Add( new Student { Id = 5, Name = \"e\", schoolClass = schoolClass6B});\n\n                context.SaveChanges();\n\n            }\n\n            var hasVacancy = admission.hasVacancy(\"6\");\n\n            Assert.AreEqual(false, hasVacancy);\n\n        }\n\n    }<\/code><\/pre>\n\n\n\n<p>Execute Tests<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"949\" height=\"245\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/07\/image-15.png?w=949\" alt=\"\" class=\"wp-image-359\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Result<\/strong><\/p>\n\n\n\n<p>We have successfully created a SchoolApp to validate school Admissions and prepared repeatable test cases using SQLite in-memory database.<\/p>\n\n\n\n<p>The complete code this Example project is available at <a href=\"https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/tree\/master\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gitlab.com\/saurabhjain1537\/nunit-sqlite-schoolapp\/-\/tree\/master<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Objective Creating repeatable Unit Test cases for a .Net applications which uses Entity Framework Core for database operations. It is recommended to write independent and repeatable test cases for the business logic. We need to handle certain cases where logic depends upon the data already existing in database. In such scenarios we can use an &hellip; <a href=\"https:\/\/saurabhjain.dev\/?p=331\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">In-memory unit test for .Net Entity Framework Application<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,17,19,22,29,40,57,61],"class_list":["post-331","post","type-post","status-publish","format-standard","hentry","category-dotnet","tag-net","tag-core","tag-dotnet","tag-entity-framework","tag-in-memory","tag-nunit","tag-sqlite","tag-unit-test"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=331"}],"version-history":[{"count":2,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/331\/revisions"}],"predecessor-version":[{"id":784,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/331\/revisions\/784"}],"wp:attachment":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}