Tuesday, October 15, 2024

Part 2 - Using Unit Tests in ASP.NET Core Application (Simple)

Unit testing in ASP.NET Core is a key aspect of writing maintainable and testable applications. In this tutorial, I'll walk you through creating a simple unit test in an ASP.NET Core application using the xUnit framework.

Prerequisites

  • .NET Core SDK installed
  • Visual Studio or any preferred IDE
  • xUnit framework

Step 1: Set Up Your ASP.NET Core Project

Create a new ASP.NET Core web application:

  1. Open Visual Studio.
  2. Select Create a new project.
  3. Choose ASP.NET Core Web Application and click Next.
  4. Name the project (e.g., SampleApp).
  5. Select ASP.NET Core Empty or MVC template depending on your needs.

Step 2: Install the xUnit Testing Framework

You need to add xUnit and xUnit Runner to your test project. In Visual Studio, right-click on the solution and:

  1. Select Add > New Project.
  2. Choose xUnit Test Project and click Next.
  3. Name the project (e.g., SampleApp.Tests) and click Create.

Once the test project is created, install any additional dependencies:

  1. Open NuGet Package Manager (right-click your SampleApp.Tests project).
  2. Search and install:
    • xUnit
    • xUnit.runner.visualstudio
    • Moq (optional, for mocking objects).

Step 3: Writing a Simple Unit Test

Let's say you have a simple service in your application that calculates tax:

1
2
3
4
5
6
7
8
// TaxService.cs in SampleApp
public class TaxService
{
    public decimal CalculateTax(decimal amount, decimal rate)
    {
        return amount * rate;
    }
}

Unit Test for TaxService

In the test project, create a test class for this service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// TaxServiceTests.cs in SampleApp.Tests
using Xunit;

public class TaxServiceTests
{
    [Fact]
    public void CalculateTax_ValidAmountAndRate_ReturnsCorrectTax()
    {
        // Arrange
        var taxService = new TaxService();
        decimal amount = 100m;
        decimal rate = 0.1m; // 10%

        // Act
        var result = taxService.CalculateTax(amount, rate);

        // Assert
        Assert.Equal(10m, result);
    }
}


Explanation:

  • [Fact]: This attribute marks the method as a test case in xUnit.
  • Arrange: Set up the test data and service.
  • Act: Call the method under test.
  • Assert: Verify that the method’s result is as expected.

Step 4: Run the Tests

To run the tests:

  1. Go to Test > Test Explorer in Visual Studio.
  2. Build the solution.
  3. The Test Explorer window should list your test. Click Run All to execute the tests.

If everything is set up correctly, your test should pass, and you'll see a green checkmark next to the test.

Step 5: Expanding Tests

You can add more tests to handle edge cases. For example, what happens when the rate is 0 or the amount is negative?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Fact]
public void CalculateTax_ZeroRate_ReturnsZero()
{
    var taxService = new TaxService();
    var result = taxService.CalculateTax(100m, 0m);
    Assert.Equal(0m, result);
}

[Fact]
public void CalculateTax_NegativeAmount_ReturnsNegativeTax()
{
    var taxService = new TaxService();
    var result = taxService.CalculateTax(-100m, 0.1m);
    Assert.Equal(-10m, result);
}


Step 6: Mocking Dependencies (Optional)

If your service has dependencies, you can use Moq to mock those. For example, if the TaxService depends on an ILogger, you can mock it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using Moq;
using Microsoft.Extensions.Logging;

[Fact]
public void CalculateTax_UsesLogger()
{
    var loggerMock = new Mock<ILogger<TaxService>>();
    var taxService = new TaxService(loggerMock.Object);
    var result = taxService.CalculateTax(100m, 0.1m);

    // Verify logger was used
    loggerMock.Verify(logger => logger.Log(
        It.IsAny<LogLevel>(),
        It.IsAny<EventId>(),
        It.IsAny<object>(),
        It.IsAny<Exception>(),
        It.IsAny<Func<object, Exception, string>>()
    ));
}

Part 1 - Unit Testing In ASP.NET Core

Introduction to Unit Testing

Unit testing is used to validate that individual components of your software (usually functions or methods) work as expected. 

Purpose of Unit Testing

Here are some key benefits:

  1. Verify correctness: Unit tests ensure that the smallest units of code behave as intended, catching bugs early.
  2. Improve code quality: Well-tested code is often cleaner and easier to maintain, as unit testing encourages developers to write more modular and clear code.
  3. Facilitate refactoring: With a solid suite of unit tests, you can refactor code confidently, knowing the tests will catch any unintended changes or breakages.
  4. Ensure reliability: Automated unit tests help reduce the chance of regression, where a new change inadvertently breaks existing functionality.
  5. Enable faster development: Once set up, unit tests can be run automatically, speeding up development by reducing the need for manual testing.

In essence, unit testing helps maintain a stable and reliable codebase, making it easier to catch issues early in the development process.

Type of Unit Testing in ASP.NET and Desktop Application In Visual Studio

  • xUnit
  • NUnit

Philosophy and Design

  • xUnit:
    • xUnit is designed with simplicity and extensibility in mind. It enforces best practices by avoiding static test methods and encourages writing isolated, easily testable code.
    • Test methods are usually instance methods, meaning a new instance of the test class is created for each test case. This encourages better isolation between tests.
  • NUnit:
    • NUnit has a more traditional approach to unit testing. It allows both static and instance test methods, which gives flexibility but can sometimes lead to less isolated tests.
    • It is older than xUnit and has a rich set of features built over time.

Creating multiple Layers Application in Visual Studio

Let’s build an ASP.NET Core MVC application with a clean architecture, separating concerns into multiple layers:

  • Business Logic Layer (BLL)
  • Data Access Layer (DAL)
  • Web API Layer
  • Presentation Layer (MVC)
  • Test Layer (Unit Testing)

The project will be organized as follows:

Project Structure

  • MyApp.Business (Business Logic Layer - BLL)
  • MyApp.Data (Data Access Layer - DAL)
  • MyApp.WebAPI (Web API Layer)
  • MyApp.Web (Presentation Layer - MVC)
  • MyApp.Tests (Test Layer)

Wednesday, June 12, 2024

LINQ Code and Tips

 LINQ Code and Tips


Entity Framework - Get a value of Column

pageTitle = db.Pages.Where(x => x.PageId == pageId).Select(x => x.PageTitle).SingleOrDefault();

Entity Framework - How to Get the current maximum value of a column

pageId = db.Pages.Max(x => x.PageId);

How to update a single colum value using EF 6 (.NET Framework)

private void MenuItem_Click(object sender, EventArgs e)
{
int index = PasswordsDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
if (index != -1)
{
// Color
ToolStripMenuItem item = (ToolStripMenuItem)sender;
string rowcolor = item.Text;
int passwordId = Convert.ToInt32(PasswordsDataGridView.Rows[index].Cells["PasswordId"].Value);
int rowcolorId = GetRowColorId(rowcolor);
using (PasswordManagerContext context = new PasswordManagerContext())
{
Password password = context.Passwords.Find(passwordId);
password.RowColor = rowcolorId;
context.SaveChanges();
}
ReloadPasswordsInDataGridView();
// Go back to original updated record ..
PasswordsDataGridView.Rows[index].Selected = true;
}
}