Feature Testing

Learning Goals

  • Define Feature Testing
  • Create a Feature Test
  • Set up a Test Database

Feature Testing

What are Feature Tests?

  • Feature tests mimic the behavior of the user: In the case of web apps, this behavior will be clicking, filling in forms, visiting new pages, etc.
  • Just like a user, the feature test should not need to know about underlying code.
  • Based on user stories

What are User Stories?

  • A tool used to communicate user needs to software developers.
  • They are used in Agile Development, and it was first introduced in 1998 by proponents of Extreme Programming.
  • They describe what a user needs to do in order to fulfill a function.
  • They are part of our “top-down” design.
As a user
When I visit the home page
And I click on the link New Task
Then I see a form to create a task

And I fill in title
And I fill in description
And I click submit
Then my task is saved

We can generalize this pattern as follows:

As a [user/user-type]
When I [action]
And I [action]
And I [action]
...
Then [expected result]

Depending on how encompassing a user story is, you may want to break a single user story into multiple, smaller user stories.

Connecting to the Prework

What type of testing that you read about yesterday is most similar to this description of Feature Tests?

Creating a Test Project

The Components of a Web Application

In order to create an environment where our test project has everything we need to create feature tests; we first need to identify what exists in our MVC application that allow us to interact with it via a client (the browser).

Any web application has two main features that need to exist in order to function:

  • Server - the server is the engine that allows the application to respond to requests. The server starts up and listens for requests. When a request is received, the server sends back the appropriate response.
  • Database - the database allows user to interact with dynamic data.

These components exist in our MVC application, and we need to create test versions of these two components in our test project.

With a Partner - Review the Program.cs file in your starter project.

  • Can you identify the code that sets up the server?
  • Can you identify the code that sets up the database?
  • Are there other files in the project that contribute to creating the server and database?

Setting Up a Test Server Environment

  1. Add a new xUnit Test Project to your Solution - call the project MvcMovie.FeatureTests.
  2. Create a Project Reference from your test project to the MvcMovie project.
  3. Install the following packages into the Test project:
    • Microsoft.Extentions.Hosting (version 0.5.0)
    • Microsoft.AspNetCore.Mvc.Testing (version 6.0.16)
  4. Add a class called Program.cs - this is where we are going to create our test server! Add the code below to this file:

     using Microsoft.AspNetCore.Builder;
     using Microsoft.AspNetCore.Hosting;
     using Microsoft.Extensions.DependencyInjection;
     using Microsoft.Extensions.Hosting;
     using MvcMovie.Controllers;
    
     namespace MvcMovie.FeatureTests
     {
         public class Program
         {
             public static void Main(string[] args)
             {
                 CreateHostBuilder(args).Build().Run();
             }
    
             public static IHostBuilder CreateHostBuilder(string[] args) =>
                 Host.CreateDefaultBuilder(args)
                     .ConfigureWebHostDefaults(webBuilder =>
                     {
                         webBuilder.ConfigureServices(services =>
                         {
                             services.AddControllersWithViews()
                                 .AddApplicationPart(typeof(HomeController).Assembly);
                         });
    
                         webBuilder.Configure(app =>
                         {
                             app.UseRouting();
                             app.UseEndpoints(endpoints =>
                             {
                                 endpoints.MapControllerRoute(
                                     name: "default",
                                     pattern: "{controller=Home}/{action=Index}/{id?}");
                             });
                         });
                     });
         }
     }
    
  5. Right-click on the test project and select Properties
  6. Scroll Down to Startup object and select McvMovie.FeatureTests.Program

With a Partner - What similarities and differences do you see between this Program.cs and the Program.cs in the MvcMovie project?

Testing Our Welcome Page

In this section, we are going to write a test for the following user story:

As a user When I visit the home page Then I see the message "Welcome"
  1. Update the UnitTest1 class to be HomeControllerTests (make sure you also re-name the file!)
  2. Update the file to match the code below:

     using Microsoft.AspNetCore.Mvc.Testing;
    
     namespace MvcMovie.FeatureTests
     {
         public class HomeControllerTests : IClassFixture<WebApplicationFactory<Program>>
         {
             private readonly WebApplicationFactory<Program> _factory;
    
             public HomeControllerTests(WebApplicationFactory<Program> factory)
             {
                 _factory = factory;
             }
    
             [Fact]
             public async Task Index_ShowsTheWelcomePage()
             {
                 var client = _factory.CreateClient();
    
                 var response = await client.GetAsync("/");
                 var html = await response.Content.ReadAsStringAsync();
    
                 response.EnsureSuccessStatusCode();
                 Assert.Contains("Welcome", html);
             }
         }
     }
    
  3. Run the tests!
Practice

In the MvcMovie projects, create a test, and the Controller and Views to satisfy this user story:

As a user When I visit "/Home/FunFacts" Then I see "The Bumble Bee Bat is the smallest mammal."

Setting up our Database Environment

  1. Install this packages into your test project:
    • Microsoft.EntityFrameworkCore.InMemory (version 7.0.5)
  2. Add a file to your test project called appsettings.json
  3. Update that file to contain the following code:

     {
         "ConnectionStrings": {
             "DefaultConnection": "Data Source=:memory:"
         }
     }
    
  4. In your test project’s Program.cs file, update the code with this database connection:

     using Microsoft.AspNetCore.Builder;
     using Microsoft.AspNetCore.Hosting;
     // You need to add one more using statement:
     using Microsoft.EntityFrameworkCore;
     using Microsoft.Extensions.DependencyInjection;
     using Microsoft.Extensions.Hosting;
     using MvcMovie.Controllers;
     using MvcMovie.DataAccess;
    
     namespace MvcMovie.FeatureTests
     {
         public class Program
         {
             public static void Main(string[] args)
             {
                 CreateHostBuilder(args).Build().Run();
             }
    
             public static IHostBuilder CreateHostBuilder(string[] args) =>
                 Host.CreateDefaultBuilder(args)
                     .ConfigureWebHostDefaults(webBuilder =>
                     {
                         webBuilder.ConfigureServices(services =>
                         {
                             //THIS IS THE CODE TO ADD:
                             services.AddDbContext<MvcMovieContext>(options =>
                                 options.UseInMemoryDatabase("TestDatabase"));
    
                             services.AddControllersWithViews()
                                 .AddApplicationPart(typeof(HomeController).Assembly);
                         });
    
                         webBuilder.Configure(app =>
                         {
                             app.UseRouting();
                             app.UseEndpoints(endpoints =>
                             {
                                 endpoints.MapControllerRoute(
                                     name: "default",
                                     pattern: "{controller=Home}/{action=Index}/{id?}");
                             });
                         });
                     });
         }
     }
    

With a Partner - What similarities and differences do you see between how we configured our database context in this Program.cs and the Program.cs in the MvcMovie project?

  1. Set the startup object for the test project
    • Right click the project, and select Properties
    • Set the Startup Object to be: MvcMovie.FeatureTest.Program

Writing an Index test

In this section, we are going to write a test for the following user story:

As a user When I visit the /movies page And Spaceballs and Young Frankenstein are in the database Then I see "Spaceballs" and "Young Frankenstein" on the page
  1. Create a new test file called MovieControllerTests.cs
  2. In that test file, add the following code:
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using MvcMovie.DataAccess;
using MvcMovie.Models;


namespace MvcMovie.FeatureTests
{
    public class MovieControllerTests : IClassFixture<WebApplicationFactory<Program>>
    {
        private readonly WebApplicationFactory<Program> _factory;

        public MovieControllerTests(WebApplicationFactory<Program> factory)
        {
            _factory = factory;
        }

        private MvcMovieContext GetDbContext()
        {
            var optionsBuilder = new DbContextOptionsBuilder<MvcMovieContext>();
            optionsBuilder.UseInMemoryDatabase("TestDatabase");

            var context = new MvcMovieContext(optionsBuilder.Options);
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            return context;
        }

        [Fact]
        public async Task Index_ReturnsViewWithMovies()
        {

        }
    }
}

With a Partner - Pseudocode what you think our test is going to look like? What kinds of things need to happen in the Arrange, Act, and Assert?

Index Test

Checks for Understanding

  • What are two components of our project that need to be recreated in our test project?
  • What do we need to do in the Arrange step of a feature test?
  • In your own words, describe the response object that we get when we call client.GetAsync("somepath");
  • Why did we need to create a GetDbContext() method in our MovieControllerTests and not our HomeControllerTests?

Lesson Search Results

Showing top 10 results