WCF Service Unit Tests Using NUnit With Rhino Mocks And Entity Framework

In this post, we will see how we can write unit test cases for our WCF Service, with a framework called NUnit. We will also be covering how to mock our dependencies in our test, here we will be using Rhino Mocks. I am going to use Visual Studio 2015 for the development. I hope you will like this article.

Please see this article in my blog here.

Download source code

Background

As a developer, we all write lots of codes in our day to day life. It is more important to check whether the codes, we have written, work well or not. So for that, we developers usually use unit testing. Only a few developers are still practicing manual testing to just check whether the functionality is working or not. I would say that is wrong. In TDD (Test Driven Development), unit testing is very important, where we actually write the test cases before we start our coding. Let us see what exactly the “Unit Testing” is.

Unit Testing

Unit testing is the process of testing a unit, it can be a class, a block of code, a function, or a property. We can easily test our units independently. In .NET, we have so many frameworks to perform the unit testing but here, we are going to use NUnit in which I found very easy to write tests.

If you have Resharper installed in your machine, it will be easier to execute and debug your tests. Here, I am using Resharper in my Visual Studio, so the screenshots will be based on that.

Now, it is time to set up our project and start our coding.

Setting up the project

To get started, please create an empty project in your Visual Studio.

UWPCoginitiveEmotion

Now, we will add a WCF Service, as follows.

Background

Once you are done, you can see two files, an Interface(IMyService) and a class (MyService) with .svc extension. If you are completely new to WCF service, I strongly recommend you read some basics here.

Now, it is time to set up our database and insert some data.

Creating a database

Here, I am creating a database with the name “TrialDB”, you can always create a DB by running the query given below.

  1. USE[master]  
  2. GO  
  3. /****** Object: Database [TrialDB] Script Date: 20-11-2016 03:54:53 PM ******/  
  4. CREATE DATABASE[TrialDB]  
  5. CONTAINMENT = NONE  
  6. ON PRIMARY(NAME = N 'TrialDB', FILENAME = N 'C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA\TrialDB.mdf', SIZE = 8192 KB, MAXSIZE = UNLIMITED, FILEGROWTH = 65536 KB)  
  7. LOG ON(NAME = N 'TrialDB_log', FILENAME = N 'C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA\TrialDB_log.ldf', SIZE = 8192 KB, MAXSIZE = 2048 GB, FILEGROWTH = 65536 KB)  
  8. GO  
  9. ALTER DATABASE[TrialDB] SET COMPATIBILITY_LEVEL = 130  
  10. GO  
  11. IF(1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))  
  12. begin  
  13. EXEC[TrialDB].[dbo].[sp_fulltext_database] @action = 'enable'  
  14. end  
  15. GO  
  16. ALTER DATABASE[TrialDB] SET ANSI_NULL_DEFAULT OFF  
  17. GO  
  18. ALTER DATABASE[TrialDB] SET ANSI_NULLS OFF  
  19. GO  
  20. ALTER DATABASE[TrialDB] SET ANSI_PADDING OFF  
  21. GO  
  22. ALTER DATABASE[TrialDB] SET ANSI_WARNINGS OFF  
  23. GO  
  24. ALTER DATABASE[TrialDB] SET ARITHABORT OFF  
  25. GO  
  26. ALTER DATABASE[TrialDB] SET AUTO_CLOSE OFF  
  27. GO  
  28. ALTER DATABASE[TrialDB] SET AUTO_SHRINK OFF  
  29. GO  
  30. ALTER DATABASE[TrialDB] SET AUTO_UPDATE_STATISTICS ON  
  31. GO  
  32. ALTER DATABASE[TrialDB] SET CURSOR_CLOSE_ON_COMMIT OFF  
  33. GO  
  34. ALTER DATABASE[TrialDB] SET CURSOR_DEFAULT GLOBAL  
  35. GO  
  36. ALTER DATABASE[TrialDB] SET CONCAT_NULL_YIELDS_NULL OFF  
  37. GO  
  38. ALTER DATABASE[TrialDB] SET NUMERIC_ROUNDABORT OFF  
  39. GO  
  40. ALTER DATABASE[TrialDB] SET QUOTED_IDENTIFIER OFF  
  41. GO  
  42. ALTER DATABASE[TrialDB] SET RECURSIVE_TRIGGERS OFF  
  43. GO  
  44. ALTER DATABASE[TrialDB] SET DISABLE_BROKER  
  45. GO  
  46. ALTER DATABASE[TrialDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF  
  47. GO  
  48. ALTER DATABASE[TrialDB] SET DATE_CORRELATION_OPTIMIZATION OFF  
  49. GO  
  50. ALTER DATABASE[TrialDB] SET TRUSTWORTHY OFF  
  51. GO  
  52. ALTER DATABASE[TrialDB] SET ALLOW_SNAPSHOT_ISOLATION OFF  
  53. GO  
  54. ALTER DATABASE[TrialDB] SET PARAMETERIZATION SIMPLE  
  55. GO  
  56. ALTER DATABASE[TrialDB] SET READ_COMMITTED_SNAPSHOT OFF  
  57. GO  
  58. ALTER DATABASE[TrialDB] SET HONOR_BROKER_PRIORITY OFF  
  59. GO  
  60. ALTER DATABASE[TrialDB] SET RECOVERY SIMPLE  
  61. GO  
  62. ALTER DATABASE[TrialDB] SET MULTI_USER  
  63. GO  
  64. ALTER DATABASE[TrialDB] SET PAGE_VERIFY CHECKSUM  
  65. GO  
  66. ALTER DATABASE[TrialDB] SET DB_CHAINING OFF  
  67. GO  
  68. ALTER DATABASE[TrialDB] SET FILESTREAM(NON_TRANSACTED_ACCESS = OFF)  
  69. GO  
  70. ALTER DATABASE[TrialDB] SET TARGET_RECOVERY_TIME = 60 SECONDS  
  71. GO  
  72. ALTER DATABASE[TrialDB] SET DELAYED_DURABILITY = DISABLED  
  73. GO  
  74. ALTER DATABASE[TrialDB] SET QUERY_STORE = OFF  
  75. GO  
  76. USE[TrialDB]  
  77. GO  
  78. ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 0;  
  79. GO  
  80. ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET MAXDOP = PRIMARY;  
  81. GO  
  82. ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF;  
  83. GO  
  84. ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET LEGACY_CARDINALITY_ESTIMATION = PRIMARY;  
  85. GO  
  86. ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING = ON;  
  87. GO  
  88. ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET PARAMETER_SNIFFING = PRIMARY;  
  89. GO  
  90. ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES = OFF;  
  91. GO  
  92. ALTER DATABASE SCOPED CONFIGURATION FOR SECONDARY SET QUERY_OPTIMIZER_HOTFIXES = PRIMARY;  
  93. GO  
  94. ALTER DATABASE[TrialDB] SET READ_WRITE  
  95. GO  
Create a table and insert data in database

To create a table, you can run the query below.
  1. USE[TrialDB]  
  2. GO  
  3. /****** Object: Table [dbo].[Course] Script Date: 20-11-2016 03:57:30 PM ******/  
  4. SET ANSI_NULLS ON  
  5. GO  
  6. SET QUOTED_IDENTIFIER ON  
  7. GO  
  8. CREATE TABLE[dbo].[Course](  
  9.     [CourseID][int] NOT NULL, [CourseName][nvarchar](50) NOT NULL, [CourseDescription][nvarchar](100) NULL, CONSTRAINT[PK_Course] PRIMARY KEY CLUSTERED(  
  10.         [CourseID] ASC) WITH(PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON[PRIMARY]) ON[PRIMARY]  
  11. GO  
  12. Now we can insert few data to our newly created table.  
  13. USE[TrialDB]  
  14. GO  
  15. INSERT INTO[dbo].[Course]  
  16.     ([CourseID], [CourseName], [CourseDescription])  
  17. VALUES(1, 'C#''Learn C# in 7 days')  
  18. INSERT INTO[dbo].[Course]  
  19.     ([CourseID], [CourseName], [CourseDescription])  
  20. VALUES(2, 'Asp.Net''Learn Asp.Net in 7 days')  
  21. INSERT INTO[dbo].[Course]  
  22.     ([CourseID], [CourseName], [CourseDescription])  
  23. VALUES(3, 'SQL''Learn SQL in 7 days')  
  24. INSERT INTO[dbo].[Course]  
  25.     ([CourseID], [CourseName], [CourseDescription])  
  26. VALUES(4, 'JavaScript''Learn JavaScript in 7 days')  
  27. GO  
So, our data is ready. That means, we are all set to write our service and tests. Now, go to your solution and create an entity data model.

Background

Entity has also been created. Now, open your interface, the platform where we start our coding. We can change the interface, as follows.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7. namespace WCF_NUnit_Tests_Rheno_Mocks {  
  8.     [ServiceContract]  
  9.     public interface IMyService {  
  10.         [OperationContract]  
  11.         Course GetCourseById(int courseId);  
  12.         [OperationContract]  
  13.         List < Course > GetAllCourses();  
  14.     }  
  15. }  
Here, we have created two operations, one to get a course by id and one to retrieve all the courses as a list. Now, please go and implement these two operations in your service file. You can modify that class, as follows.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7. namespace WCF_NUnit_Tests_Rheno_Mocks {  
  8.     public class MyService: IMyService {  
  9.         private static MyEntity _myContext;  
  10.         private static IMyService _myIService;  
  11.         public MyService() {}  
  12.         public MyService(IMyService myIService) {  
  13.             _myContext = new MyEntity();  
  14.             _myIService = myIService;  
  15.         }  
  16.         public Course GetCourseById(int courseId) {  
  17.             var crse = _myContext.Courses.FirstOrDefault(dt => dt.CourseID == courseId);  
  18.             return crse;  
  19.         }  
  20.         public List < Course > GetAllCourses() {  
  21.             var courses = (from dt in _myContext.Courses select dt).ToList();  
  22.             return courses;  
  23.         }  
  24.     }  
  25. }  
In the above code, as you can see, we are creating two constructors; one is without parameter and other is with parameter, and we are having IMyService as a parameter. In this way we can achieve the dependency injection when we write tests for our unit. So, what we need to do is just to pass the dependency. In this case, it is IMyService.

In software engineering, dependency injection is a software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it. Source: WikiPedia

If you need to know more on dependency injection, please read it here. Now, we will build and check whether our service is working fine or not. Please press CTRL+F5.

Background

As our services are ready, we can now create the tests for those operations. For that, we can create a new class library in our project and name it as UnitTest.Service. Please add a class MyServiceTests in the class library where we can add our tests. And please, do not forget to add our application reference too.

Background

Installing and configuring NUnit

Now, we can install NUnit to our test project from NuGet Package. Once you add the package, you will be able to add the preceding namespace in our MyServiceTests class.

using NUnit.Framework;

In NUnit, we have so many attributes that can be used for different purposes, but now, we are going to use only four among them.
  1. TestFixture

    Background

  2. OneTimeSetUp



    In previous versions, we were using TestFixtureSetUp, as the TestFixtureSetUp is obsolete. Now, we are using OneTimeSetUp.

    Background

    TearDown

    This attribute is used to identify a method that is called immediately after each test, it will be called even if there is any error, this is the place we can dispose our objects.

    Test

    This attribute is used to make a method callable from NUnit test runner. This cannot be inherited.

    Now, we can see all these attributes in action. So, let us write some tests, but the real problem is that we need to mock the IMyService right as the parameterized constructor of the class MyService expecting it. Remember, we have discussed about setting up our services in the way which can be injected the dependencies? No worries, we can install Rhino Mock for that now.

    Background

    So, we can add the tests and dependencies, as follow, in our test class.
    1. using NUnit.Framework;  
    2. using Rhino.Mocks;  
    3. using WCF_NUnit_Tests_Rhino_Mocks;  
    4. namespace UnitTest.Service {  
    5.         [TestFixture]  
    6.         public class MyServiceTests {  
    7.             private static MyService _myService;  
    8.             private IMyService _myIservice;  
    9.             [OneTimeSetUp]  
    10.             public void SetUp() {  
    11.                     _myIservice = MockRepository.GenerateMock < IMyService > ();  
    12.                     _myService = new MyService(_myIservice);  
    13.                 }  
    14.                 [TearDown]  
    15.             public void Clean() {}  
    16.                 [Test(Description = "A test to check whether the returned value is null")]  
    17.             public void GetCourseById_Return_NotNull_Pass() {  
    18.                     //Set Up  
    19.                     var crs = new Course {  
    20.                         CourseID = 1,  
    21.                             CourseName = "C#",  
    22.                             CourseDescription = "Learn course in 7 days"  
    23.                     };  
    24.                     _myIservice.Stub(dt => dt.GetCourseById(1)).IgnoreArguments().Return(crs);  
    25.                     //Act  
    26.                     crs = _myService.GetCourseById(1);  
    27.                     //Assert  
    28.                     Assert.IsNotNull(crs, "The returned value is null");  
    29.                 }  
    30.                 [Test(Description = "A test to check we get all the courses")]  
    31.             public void GetAllCourses_Return_List_Count_Pass() {  
    32.                 //Act  
    33.                 var crs = _myService.GetAllCourses();  
    34.                 //Assert  
    35.                 Assert.AreEqual(4, crs.Count, "The count of retrieved data doesn't match");  
    36.                 _myIservice.VerifyAllExpectations();  
    37.             }  
    38.         }  
    39.     } // This is just a sample script. Paste your real code (javascript or HTML) here.  
    40. if ('this_is' == /an_example/) {  
    41.     of_beautifier();  
    42. else {  
    43.     var a = b ? (c % d) : e[f];  
    44. }  
    As you can see, we have mocked our IMyService as follows.

    myIservice = MockRepository.GenerateMock<IMyService>();

    Background

    And, in the test GetCourseById_Return_NotNull_Pass, we have also used a method called Stub. Stub actually tells the mock object to perform a certain action when a matching method is called, and it doesn’t create an expectation for the same. So, you might be thinking, how can we create an expectation? For that we have a method called Expect.

    Background

    It is always recommended to verify your expectation when you use Expect as we used it in our test GetAllCourses_Return_List_Count_Pass.

    myIservice.VerifyAllExpectations();

    As I already said, I am using Resharper, we have so many shortcuts to run our tests, now if you right click on your TestFixture, you can see a run all options as preceding.

    Background

    As I was getting an error, “No connection string named ‘Entity’ could be found in the application config file,” when I ran the tests, I was forced to install the Entity framework in my test project and also to add a new config file with the connection string like we have in our web config file.

    If everything goes fine and you don’t have any errors, I am sure you will get a screen as preceding.

    Background

Happy coding

See also

Conclusion

Did I miss anything that you may think is needed? Did you find this post useful? I hope you liked this article. Please share with me your valuable suggestions and feedback.

Your turn. What do you think?

A blog isn’t a blog without comments, but do try to stay on topic. If you have a question unrelated to this post, you’re better off posting it on C# Corner, Code Project, Stack Overflow, ASP.Net Forum instead of commenting here. Tweet or email me a link to your question there, and I’ll definitely try to help if I can.