Monday, April 16, 2018

ASP.Net Core 2 with Postgresql on Linux Part 7: The Service Layer

In Part I, I discussed the rationale for porting a ASP.Net Core 2 app to my Linux system replacing SQL Server with Postgresql and place it on Heroku. 

With Part II, we transferred the SQL Server data to Postgres.


In Part III, I create the ASP.Net MVC Core 2.x app, from which we will proceed, and get Entity Framework Core installed.


Then in Part IV, I look at the configuration differences between the ASP.Net MVC app that uses SQL Server and the new app, in preparation of porting the old app to use Postgresql.

Part V, we compared the differences in both the projects' structures and ported the existing project code, starting with the data model layer, to the new project. In addition to this, we got the jquery.countdown jquery plugin installed, that is used to implement a JavaScript timer. More on that in a later article. Finally, we used the dotnet ef dbcontext scaffold command that builds a DbContext and entity types for out Postgresql database. And, oh yes, we added the project to github, which frankly should have been done day one.


In Part VI, we got the NUnit testing framework in place 
in order to test both the new and future code.


In this post, we will get the Service layer setup in order to unit test which will test the Data and Model tiers as well.

Using the Beyond Compare tool, let's look at the differences between the existing ASP.Net MVC app and the new project concerning the Service tier:



As you can see, there are no Service classes in the right side, which is the new app, of the folder-level comparison. 

Instead of simply copying all the Service layer code to the new app with Beyond Compare, let's add one class at a time, setting up unit test for each one. 

The first one we will copy is the EsvService.cs class. Also, you will note that in the above image, there is a IEsvService.cs file as well as EsvService. The IEsvService is an interface class. Here is a section of code from the EsvService.cs file:

  public class EsvService : ServiceBase, IEsvService  
 {  
      private static string ApiKey  
      {  
        get { return "myKey"; }  
      }  
      private static DateTime TodaysDate  
      {  
        get { return GetESTDate(); }  
      }  
 //......  
 }  

Here is the updated code that contains the interface class as well as the implementation:


  public interface IEsvService  
 {  
      Task<string> GetVerseAsync(string verseReference);  
      Task<string> GetDailyVerseAsync();  
      Task<string> GetTodaysPsalmAsync();  
 }  
 public class EsvService: ServiceBase, IEsvService  
      {  
      private static string ApiKey  
      {  
        get { return "myKey"; }  
      }  
      private static DateTime TodaysDate  
      {  
        get { return GetESTDate(); }  
      }  
 //...       
 }  

I find this easier to manage when changes are made to the interface since you are already in the correct location to update the implementation class, EsvService, in this case. Also, you will note that the class implements the ServiceBase class. Therefore, I will move that to the new app as well. After updating the namespace in the new code, the project compiled and all is well.

At any time if you want to view the source code, go here.

Next, let's get a reference set to the myApp project from the UnitTest project.


 $ dotnet add reference ../myApp/myApp.csproj  


After adding the myApp project, which is the system under test (SUT), I added a few test methods:



Then, as you can see from above, I issued the dotnet test command and all passed. 

However, we really do not want to run tests we are depending on outside resources each time. While that type of test is valuable, it is what is referred to as an integration test and should only be run as needed. Here, we just want to test our code and not the dependencies. Enter, Moq, the mock testing framework that helps you mock or fake the dependencies and just tests your code.


 $ dotnet add package Moq  




Then, I updated the existing Service test methods and moved integration tests to a separate class. In order to run the standard mocked unit tests separately, I employed NUnit's Category Attribute.




Then, I ran dotnet test --filter TestCategory=Unit, and here is the result:




After this, I ported the remaining Service classes from the existing ASP.Net MVC app to this one. Looking at the comparison there are several classes that were moved.

As I mentioned above, I moved the interface classes into the same file as their implementation classes. Therefore, the classes starting with "I" are not in the new app.

Now that we have the Data, Model, and Service layer classes ported, next in Part VIII, we will import the Controller classes from the existing to the app and setup unit tests for them.



No comments: