Skip to content
  • iImagine
  • Register
  • Log In

Web Development School

Learning made easy.

  • Books
    • Beginning Web Development with ASP.Net Core & Client-Side Technologies
      • TOC
      • Part 1
        • Chapter 1: Static HTML – Designing the landing page
      • Part 2
        • Chapter 2: ASP.Net Core – Let’s talk Dynamic
        • Chapter 3: Introduction to ASP.Net Core MVC
          [ASP.Net Core v9]
      • Part 4
        • Chapter 7: Using Server Side & Client Side technologies together
          [ASP.Net Core v7 & Angular 15]
  • Environment Setup
    • Installing Angular
    • Installing Visual Studio 2022
    • Installing SQL Server 2022 Express
    • Installing Postman
    • Installing Git for Windows
  • Blog
  • iImagine WebSolutions
  • Events
  • Learning Videos
  • Toggle search form

Unit Test: Paging in the Vehicles controller

In the last module we learned how to implement the repository pattern and created a Vehicle Repository for the application. Now that the Vehicle controller is using an interface to access the Vehicle data we can create some unit tests for its HTTP GET method.

Note: The pathway I am using for development in this module is: C:\Development\FredsCars\FullStack\Module26.
Table Of Contents
  1. Create a Vehicles Controller Test: CanReturnDefaultPage
    • Run the CanReturnDefaultPage test in Test Explorer
    • Run the CanReturnDefaultPage test with DotNet CLI: dotnet test –filter switch
  2. Create Vehicles Controller Test 2: CanReturnSelectedPage
  3. Create Vehicles Controller Test 3: CanReturnPagingInfo
  4. Run the Vehicles controller tests
  5. What's Next

Create a Vehicles Controller Test: CanReturnDefaultPage

Create a new folder called Controllers on the root of the FredsCarsAPI.Tests project. In the new folder create a class file called VehiclesControllerTests.cs and fill it with the contents below.

FredsCarsAPI.Tests/Controllers/VehiclesControllerTests.cs

using Moq;
using MockQueryable.Moq;
using FredsCarsAPI.Controllers;
using FredsCarsAPI.Repositories;
using FredsCarsAPI.Models;
using FredsCarsAPI.Models.DTOs;
using FredsCarsAPI.Data;

namespace FredsCarsAPI.Tests.Controllers
{
    public class VehiclesControllerTests
    {
        private List<Vehicle> _testData =
            new List<Vehicle>
            {
                new Vehicle { Id = 1,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M1",
                    Model = "M1",
                    Color = "C1",
                    Price = 64000,
                    VIN = "123",
                    VehicleTypeId = 1,
                    VehicleType = new VehicleType { Id = 1, Name = "Car" } 
                },
                new Vehicle { Id = 2,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M2",
                    Model = "M2",
                    Color = "C2",
                    Price = 64000,
                    VIN = "456",
                    VehicleTypeId = 2,
                    VehicleType = new VehicleType { Id = 2, Name = "Truck" }
                },
                new Vehicle { Id = 3,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M3",
                    Model = "M3",
                    Color = "C3",
                    Price = 64000,
                    VIN = "789",
                    VehicleTypeId = 3,
                    VehicleType = new VehicleType { Id = 3, Name = "Jeep" }
                },
                new Vehicle { Id = 4,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M4",
                    Model = "M4",
                    Color = "C4",
                    Price = 64000,
                    VIN = "012",
                    VehicleTypeId = 1,
                    VehicleType = new VehicleType { Id = 1, Name = "Car" }
                },
                new Vehicle { Id = 5,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M5",
                    Model = "M5",
                    Color = "C5",
                    Price = 64000,
                    VIN = "345",
                    VehicleTypeId = 2,
                    VehicleType = new VehicleType { Id = 2, Name = "Truck" }
                },
                new Vehicle { Id = 6,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M6",
                    Model = "M6",
                    Color = "C6",
                    Price = 64000,
                    VIN = "678",
                    VehicleTypeId = 3,
                    VehicleType = new VehicleType { Id = 3, Name = "Jeep" }
                },
                new Vehicle { Id = 7,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M7",
                    Model = "M7",
                    Color = "C7",
                    Price = 64000,
                    VIN = "901",
                    VehicleTypeId = 1,
                    VehicleType = new VehicleType { Id = 1, Name = "Car" }
                },
                new Vehicle { Id = 8,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M8",
                    Model = "M8",
                    Color = "C8",
                    Price = 64000,
                    VIN = "234",
                    VehicleTypeId = 2,
                    VehicleType = new VehicleType { Id = 2, Name = "Truck" }
                },
                new Vehicle { Id = 9,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M9",
                    Model = "M9",
                    Color = "C9",
                    Price = 64000,
                    VIN = "567",
                    VehicleTypeId = 3,
                    VehicleType = new VehicleType { Id = 3, Name = "Jeep" }
                },
                new Vehicle { Id = 10,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M10",
                    Model = "M10",
                    Color = "C10",
                    Price = 64000,
                    VIN = "890",
                    VehicleTypeId = 1,
                    VehicleType = new VehicleType { Id = 1, Name = "Car" }
                },
                new Vehicle { Id = 11,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M11",
                    Model = "M11",
                    Color = "C11",
                    Price = 64000,
                    VIN = "abc",
                    VehicleTypeId = 2,
                    VehicleType = new VehicleType { Id = 2, Name = "Truck" }
                },
                new Vehicle { Id = 12,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M12",
                    Model = "M12",
                    Color = "C12",
                    Price = 64000,
                    VIN = "def",
                    VehicleTypeId = 3,
                    VehicleType = new VehicleType { Id = 3, Name = "Jeep" }
                },
                new Vehicle { Id = 13,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M13",
                    Model = "M13",
                    Color = "C13",
                    Price = 64000,
                    VIN = "ghi",
                    VehicleTypeId = 1,
                    VehicleType = new VehicleType { Id = 1, Name = "Car" }
                },
                new Vehicle { Id = 14,
                    Status = Status.New,
                    Year = "2022",
                    Make = "M14",
                    Model = "M14",
                    Color = "C14",
                    Price = 64000,
                    VIN = "jkl",
                    VehicleTypeId = 2,
                    VehicleType = new VehicleType { Id = 2, Name = "Truck" }
                },
            };

        [Fact]
        public async Task CanReturnDefaultPage()
        {
            // Arrange
            // Create the mock from the test data
            Mock<IVehicleRepository> mockVehicleRepo =
                new Mock<IVehicleRepository>();

            var mockVehicleIQueryable =
                _testData.AsQueryable().BuildMock();
            mockVehicleRepo.Setup(m => m.Vehicles).Returns(mockVehicleIQueryable);

            var controller = new VehiclesController(mockVehicleRepo.Object);
            
            // Act
            ApiResult<VehicleDTO> result = await controller.GetVehicles();

            // Assert
            Assert.True(result.Data.Count == 10);
            Assert.True(result.Data[0].Id == 1
                && result.Data[9].Id == 10);
        }
    }
}

Run the CanReturnDefaultPage test in Test Explorer

Right click on the CanReturnDefaultPage test in Test Explorer and select Run.

The test should pass and and display a green checkmark.


Note: When I introduced this test, CanReturnDefaultPage, into the project, I was surprised to run into a little trouble. I could right click a test and run it in Test Explorer with no problem. But if I tried to run all of the test it would hang and I would have to kill the testhost.exe in the Task Manager. But it seemed to be ok if I ran all tests. If you ever run into trouble in Test Explorer you can use the command line as an alternative. You can run all tests using the dotnet test command like we learned in module 24, or you can filter tests and run a specific one as I show in the next section using the dotnet test command’s
--filter switch.
However, what worked seemed to work for me in getting Test Explorer running smoothly again was updatating the xunit.runner.visualstudio package to version 2.5.4. You can do this in the Nuget Package Manager or through the command line with the following command in a command prompt pointed to the FredsCarsAPI.Tests project.
dotnet add package xunit.runner.visualstudio --version 2.5.4


Run the CanReturnDefaultPage test with DotNet CLI: dotnet test –filter switch

We can also run the single test from the command line with the dotnet test CLI command we saw in the module 24. Open a command line and navigate to the FredsCarsAPI.Tests project and run the following command.

dotnet test --filter "FullyQualifiedName=FredsCarsAPI.Tests.Controllers.VehiclesControllerTests.CanReturnDefaultPage"

The results should look similar to the following.

This time in the DotNet CLI we used the dotnet test command but here we also used the
--filter switch to specify the test to run. After the filter switch we have in quotes FullyQualifiedName=[path to test]. This should be the namespace of the class followed by the class name followed by the test name all separated by dots.

namespaceOfTest.classNameOfTest.TesName

Now let’s return to the actual test code itself and inspect what we did there.

The first thing we did in the VehiclesControllerTests class is setup some Vehicle test data as a List<Vehicle> and assign it to a private variable called _testData.

Next we created a test method for our first Vehicles controller test called CanReturnDefaultPage and made it asynchronous.

In the next arrange section, the first three lines use a combination of the original moq package to mock an IVehicleRepository in a variable called mockVehicleRepo and the new MockQueryable.Moq extension for moq to convert our test data to a mock IQueryable in a variable called mockVehicleIQueryable. The third line sets up the Mock VehicleRepository to have its Vehicles IQueryable Property return the Mock Vehicle IQueryable test data.

Finally at the end of the arrange section we instantiate a new Vehicles controller and pass to its constructor the Mock Vehicle Repository which now contains the Mock IQueryable of test data and assign it to a variable called controller.

In the act section we simply call the GetVehicles method of the controller and assign the result to a variable named result. The controller should now have everything it needs to return an ApiResult since we passed it the Vehicle Repository with test data.

We then make two assertions in the assert section.

Number one, we assert that the Count of VehicleDTO objects returned in the Data property of the ApiResult will be 10. This is because we did not specify any values for the optional parameters pageIndex and pageSize for the GetVehicles method in the Vehicles controller. The default values are 0 and 10 respectively. So we should expect a pageSize of 10 since that is the default value for pageSize.

Next we assert that the first (index 0) and tenth or last (index 9) VehicleDTO object Ids in the ApiResult Data property are 1 and 10. If we look back at the _testData data in the VehiclesControllerTests class, this would be the case using the default pageIndex and pageSize values where pageIndex of 0 means grab the first page of pageSize (10 in this case) records.

Create Vehicles Controller Test 2: CanReturnSelectedPage

In the VehiclesControllerTests.cs file, add the second test by modifying its contents with the following in bold blue font.

FredsCarsAPI.Tests/Controllers/VehiclesControllerTests.cs

/*** existing code ***/
        [Fact]
        public async Task CanReturnDefaultPage()
        {
            // Arrange
            // Create the mock from the test data
            Mock<IVehicleRepository> mockVehicleRepo =
                new Mock<IVehicleRepository>();

            var mockVehicleIQueryable =
                _testData.AsQueryable().BuildMock();
            mockVehicleRepo.Setup(m => m.Vehicles).Returns(mockVehicleIQueryable);

            var controller = new VehiclesController(mockVehicleRepo.Object);
            
            // Act
            ApiResult<VehicleDTO> result = await controller.GetVehicles();

            // Assert
            Assert.True(result.Data.Count == 10);
            Assert.True(result.Data[0].Id == 1
                && result.Data[9].Id == 10);
        }

        [Fact]
        public async Task CanReturnSelectedPage()
        {
            // Arrange
            // Create the mock from the test data
            Mock<IVehicleRepository> mockVehicleRepo =
                new Mock<IVehicleRepository>();

            var mockVehicleIQueryable =
                _testData.AsQueryable().BuildMock();
            mockVehicleRepo.Setup(m => m.Vehicles).Returns(mockVehicleIQueryable);

            var controller = new VehiclesController(mockVehicleRepo.Object);

            // Act
            ApiResult<VehicleDTO> result =
                await controller.GetVehicles(3, 3);

            // Assert
            Assert.True(result.Data.Count == 3);
            Assert.True(result.Data[0].Id == 10
                && result.Data[2].Id == 12);
        }
    }
}

In the test code above for our second test, where we are testing to see if we can return a specific page, the arrange section is the same as the first test. We build up our mocks for the Vehicle Repository and IQueryable<Vehicle> that the repository returns.

The act section is also very similar except that it passes pageIndex and pageSize values to the controller’s GetVehicles method.

In the assert section we are checking that the page we specified in the act section is indeed returned.
Our assertions here are also very similar to the first test.
We assert that the data count is 3 as we specify in the controller method call of the act section.
And then we assert that the first record (index 0) and the last record (index 2, the last of three records) have Ids of 10 and 12.
This should be true according to our _testData field contents as a pageIndex of 3 is the fourth page. So we skip 3 X 3 = 9 records and start on the Id of 10. And we take 3 records to end at an Id of 12.

Create Vehicles Controller Test 3: CanReturnPagingInfo

In the VehiclesControllerTests.cs file add the last test as shown below in bold blue font.

FredsCarsAPI.Tests/Controllers/VehiclesControllerTests.cs

/*** existing code ***/

        [Fact]
        public async Task CanReturnPagingInfo()
        {
            // Arrange
            // Create the mock from the test data
            Mock<IVehicleRepository> mockVehicleRepo =
                new Mock<IVehicleRepository>();

            var mockVehicleIQueryable =
                _testData.AsQueryable().BuildMock();
            mockVehicleRepo.Setup(m => m.Vehicles).Returns(mockVehicleIQueryable);

            var controller = new VehiclesController(mockVehicleRepo.Object);

            // Act
            ApiResult<VehicleDTO> result =
                await controller.GetVehicles(1, 5);

            // Assert
            Assert.True(result.Data.Count == 5);
            Assert.True(result.PageIndex == 1);
            Assert.True(result.PageSize == 5);
            Assert.True(result.TotalCount == 14);
            Assert.True(result.TotalPages == 3);
        }
    }
}

In the code above for our third test, where we are testing for the correct return of paging info, the arrange and act sections are again very similar to the first two tests. The only difference being that we are now passing different pageIndex and pageSize values; this time 1 and 5 respectively.

In the assert section we check the PageIndex and PageSize properties of the result are what we specified in the Vehicles controller GetVehicles call, the total count of data in the repository is 14 which is indeed the number of Vehicles we have in our private _testData field, and that the total page count is 3 (total count / pageSize) = (14 / 5 rounded up).

Run the Vehicles controller tests

Now in Test Explorer, if you right click on the VehiclesControllerTests group and select Run, all three Vehicle controller tests will pass and show a green check mark.

What’s Next

We’ve been working very hard since module 23 to rework our paging to work on the server side and have refactored our Web API project to isolate all of our components to make testing easier and to try and give all of our components a single responsibility. Along the way we have implemented some popular software patterns namely Dependency Injection and the Repository pattern.

It took a little work but we have a solid architecture at this point for paging and should be able to incorporate server-side sorting relatively easy. And that is what we’ll turn to in the next module. We are going to implement server-side sorting and put back that functionality we temporarily dismantled so we could concentrate on paging.

< Prev
Next >

Leave a ReplyCancel reply

Chapter 1: Static HTML – Designing the landing page.

  • Static HTML – Designing the landing page.
  • Let’s get started!
  • Mock your site with HTML
  • Make CSS easy with Bootstrap
  • Mock your content
  • Introducing JavaScript
  • JavaScript Code Improvements
  • Results Data
  • Images and the HTML Image Element.
  • Revisiting Reusability for CSS and JavaScript
  • Reuse for HTML: PART 1
  • Reuse for HTML: PART 2
  • Details Page – Using a Bootstrap Component
  • Creating Links
  • Chapter One Conclusion

Chapter 2: ASP.Net Core – Let’s talk Dynamic

  • Introduction to ASP.Net Core
  • What is .Net?
  • What is ASP.Net
  • Introduction to Entity Framework Core

Chapter 3: ASP.Net MVC Core – Models, Views, and Controllers [ASP.Net Core v9]

  • Introduction to ASP.Net Core MVC
  • Create the project: ASP.Net Core MVC
  • Explore the ASP.Net Core Empty Web Project Template
  • Configure the Application for MVC
  • Create a Controller: Home Controller
  • Create a View: Index View for the Home Controller
  • Install Bootstrap using Libman
  • Create the Layout template
  • Create the Model
  • Install EF Core & Create the Database
  • Seed the Database: Loading test data
  • DI (Dependency Injection): Display a List of Vehicles
  • Repository Pattern: The Vehicles Repo
  • Unit Test 1: Home Controller Can Use Vehicle Repository
  • Unit Test 2: Vehicle Repository Can Return List
  • Add the ImagePath Migration and Thumbnail images to results
  • Pagination: Create a Custom Tag Helper
  • Sorting
  • Category Filter
  • Partial View: Break out the vehicle results
  • View Component: Create dynamic category buttons
  • Create the Details page
  • Create the Create Page

Chapter 7: Using Server Side & Client Side technologies together. [ASP.Net Core v7 & Angular v15]

  • Intro to Full Stack Development
  • Fred’s Cars – Full Stack Development
  • Prepare the environment
  • Create the Visual Studio Solution
  • Add the ASP.Net Core Web API project
  • Add the Angular Project
  • Wire it up!
  • WeatherForecast: Understanding the basics
  • Vehicles API Controller: Mock Data
  • Vehicles Angular Component: Consuming Data
  • Routing and Navigation
  • Using a Component Library: Angular Material
  • Our first Angular Material Component: MatToolbar
  • Configuring for Saas: CSS with superpowers
  • Create the Header & Footer components
  • Displaying Results with MatTable
  • Loading: Using a Progress Spinner
  • MatTable: Client-Side Paging and Sorting
  • MatSidenav: Create a Search Sidebar
  • MatCheckbox: Category Search UI
  • Adding an image to the welcome page
  • Create the database with Entity Framework Core migrations
  • MatPaginator & PageEvent: Custom Server-Side Paging
  • Unit Testing: Custom Server-Side Paging
  • Repository Pattern: VehicleRepository
  • Unit Test: Paging in the Vehicles controller
  • Server-Side Sorting
  • Unit Tests: Sorting
  • Filter (Quick Search)
  • Unit Tests: Filter feature
  • Advanced Search: Categories
  • Unit Tests: Search by category
  • Progress Spinner: Final Fix

TOC

  • What were WebForms?
  • Enter MVC
    • Understanding MVC
    • Advantages of MVC
  • ASP.Net Core MVC – A total rewrite
  • ASP.Net Core 2 MVC – Here come Razor Pages
    • Understanding Razor Pages
  • ASP.Net Core 3 – Dropping the MVC reference
    • Understanding Blazor
  • Dropping the MVC reference
  • Hello .Net 5!
  • What’s Next? – Here comes .Net 6.

Recent Posts

  • Angular Commands Cheat Sheet
  • Installing Git for Windows
  • Installing Postman
  • Installing SQL Server 2022 Express
  • Installing Visual Studio 2022

Recent Comments

No comments to show.

Archives

  • November 2023
  • October 2023
  • June 2023
  • October 2021

Categories

  • Angular
  • ASP.Net
  • Environment Setup
  • See All
  • SQL Server
  • Visual Studio
  • Web API & Rest Services

WordPress Theme Editor

Copyright © 2025 Web Development School.

Powered by PressBook Blog WordPress theme