Dotnet Core Web API unit testing interview questions and answers

Dotnet Core Web API unit testing interview questions and answers


1. What is unit testing in .NET Core?

Answer:
Unit testing is a process of testing individual units or components of a software system to ensure that each part functions correctly. In the context of .NET Core Web API, unit testing typically involves testing controllers, services, or other business logic in isolation. The goal is to verify that methods return the expected results for various inputs and conditions.

2. What is the difference between unit testing and integration testing?

Answer:

  • Unit Testing: Tests individual components in isolation, focusing on small pieces of code (e.g., a method, a class). It mocks external dependencies to test the logic of the component itself.
  • Integration Testing: Focuses on testing how multiple components work together. It typically involves real interactions with databases, file systems, or external APIs, rather than mocking dependencies.

3. What is the purpose of mocking in unit tests?

Answer:
Mocking is used to simulate external dependencies (like databases, APIs, or services) in unit tests. This allows you to isolate the component under test and ensure that the test is focused on the unit itself, without being affected by external systems. Mocks help simulate different scenarios, including success and failure conditions.

4. What testing frameworks are commonly used in .NET Core?

Answer:
Some of the most common testing frameworks in .NET Core include:

  • xUnit: A popular open-source testing framework for .NET, designed to be simple and extensible.
  • NUnit: Another widely used testing framework, offering more features and flexibility than xUnit.
  • MSTest: The default test framework from Microsoft, suitable for unit and integration tests.
  • Moq: A popular mocking framework used to mock dependencies in unit tests.

5. How do you test a Web API controller in .NET Core?

Answer:
To test a Web API controller in .NET Core, you can use the following approach:

  • Use xUnit, NUnit, or MSTest for the test framework.
  • Use Moq to mock external dependencies such as services or repositories.
  • You can create a test project and set up an instance of the controller, passing in mocked dependencies.
  • Use ASP.NET Core's TestServer (part of Microsoft.AspNetCore.TestHost) to simulate HTTP requests and test actions like GET, POST, etc.

Example:

[Fact]

public async Task Get_ReturnsOkResult_WithListOfItems()

{

    // Arrange

    var mockService = new Mock<IItemService>();

    mockService.Setup(service => service.GetItemsAsync())

               .ReturnsAsync(new List<Item> { new Item(), new Item() });

    var controller = new ItemsController(mockService.Object);

 

    // Act

    var result = await controller.Get();

 

    // Assert

    var okResult = Assert.IsType<OkObjectResult>(result);

    var items = Assert.IsType<List<Item>>(okResult.Value);

    Assert.Equal(2, items.Count);

}

6. How do you test a service class that has dependencies on a repository in .NET Core?

Answer:

  • First, you can mock the repository to simulate interactions with the data layer without actually querying a real database.
  • Then, you can create an instance of the service class and inject the mocked repository to test the logic in the service.

Example:

[Fact]

public void CreateUser_ShouldCallRepositoryOnce()

{

    // Arrange

    var mockRepo = new Mock<IUserRepository>();

    var userService = new UserService(mockRepo.Object);

    var user = new User { Name = "John Doe" };

 

    // Act

    userService.CreateUser(user);

 

    // Assert

    mockRepo.Verify(repo => repo.AddUser(It.IsAny<User>()), Times.Once());

}

7. What is dependency injection (DI) in .NET Core, and how does it relate to unit testing?

Answer:
Dependency Injection (DI) is a design pattern used to achieve Inversion of Control (IoC) by passing dependencies into a class rather than having the class create them itself. This makes it easier to swap out dependencies with mock objects or stubs for unit testing. In unit tests, DI is used to inject mock implementations of dependencies, which ensures that the class under test is isolated.

8. What is the purpose of the [Fact] and [Theory] attributes in xUnit?

Answer:

  • [Fact]: Marks a test method that has no parameters and runs independently. It is used for simple unit tests where no input data is required.
  • [Theory]: Marks a test method that has parameters. It allows you to run the same test with different sets of input data, making it useful for parameterized tests.

Example:

[Theory]

[InlineData(1, 2, 3)]

[InlineData(2, 2, 4)]

public void Add_ShouldReturnCorrectResult(int a, int b, int expected)

{

    // Arrange

    var calculator = new Calculator();

 

    // Act

    var result = calculator.Add(a, b);

 

    // Assert

    Assert.Equal(expected, result);

}

9. How would you test a method that calls an external API in .NET Core?

Answer:
You can use mocking to simulate the behavior of the external API. For instance, if the method relies on a third-party HTTP client or an external service, you would mock the HTTP calls or services. This ensures that the unit test doesn't make actual network requests.

Example:

[Fact]

public async Task FetchWeatherData_ShouldReturnWeatherDetails()

{

    // Arrange

    var mockHttpClient = new Mock<IHttpClientWrapper>();

    mockHttpClient.Setup(client => client.GetAsync(It.IsAny<string>()))

                  .ReturnsAsync(new HttpResponseMessage

                  {

                      StatusCode = HttpStatusCode.OK,

                      Content = new StringContent("{ 'temperature': 25 }")

                  });

 

    var weatherService = new WeatherService(mockHttpClient.Object);

 

    // Act

    var weather = await weatherService.GetWeatherData("London");

 

    // Assert

    Assert.Equal(25, weather.Temperature);

}

10. What is a "test double"?

Answer:
A test double is a general term for objects used in unit tests that replace real implementations to simulate behavior. There are different types of test doubles:

  • Mocks: Objects pre-programmed with expectations, used to verify interactions.
  • Stubs: Provide predefined responses to calls made during the test.
  • Fakes: Provide a working implementation of the dependency, but not a full one (e.g., an in-memory database).
  • Spies: Track how an object was used, like a mock but with an emphasis on capturing details of method calls.

11. How do you handle exceptions in unit tests?

Answer:
You can handle exceptions in unit tests by asserting that specific exceptions are thrown during the test. In xUnit, you can use the Assert.Throws<TException> method to verify that a specific exception is thrown under certain conditions.

Example:

[Fact]

public void Divide_ByZero_ShouldThrowArgumentException()

{

    // Arrange

    var calculator = new Calculator();

 

    // Act & Assert

    var exception = Assert.Throws<ArgumentException>(() => calculator.Divide(10, 0));

    Assert.Equal("Cannot divide by zero", exception.Message);

}

 

12. What is the difference between Assert.Equal and Assert.Same in xUnit?

Answer:

  • Assert.Equal(expected, actual): This checks if the values of the expected and actual objects are the same. It compares the actual content or value of the objects.
  • Assert.Same(expected, actual): This checks if both the expected and actual values refer to the same object in memory. It verifies the object identity (i.e., both references point to the same object).

Example:

var obj1 = new Person { Name = "John" };

var obj2 = new Person { Name = "John" };

Assert.Equal(obj1, obj2); // Passes (they have the same value, but different references)

Assert.Same(obj1, obj2);  // Fails (they are not the same reference)

13. How do you test asynchronous methods in .NET Core Web API?

Answer:
Asynchronous methods are tested similarly to synchronous methods, but you need to use async and await to handle the asynchronous execution. In xUnit, for example, you can use await to call asynchronous methods and assert their results.

Example:

[Fact]

public async Task GetWeatherAsync_ShouldReturnWeatherData()

{

    // Arrange

    var mockService = new Mock<IWeatherService>();

    mockService.Setup(service => service.GetWeatherAsync("New York"))

               .ReturnsAsync(new Weather { Temperature = 75 });

 

    var controller = new WeatherController(mockService.Object);

 

    // Act

    var result = await controller.GetWeather("New York");

 

    // Assert

    var okResult = Assert.IsType<OkObjectResult>(result);

    var weatherData = Assert.IsType<Weather>(okResult.Value);

    Assert.Equal(75, weatherData.Temperature);

}

14. What is the role of the TestServer in .NET Core testing?

Answer:
TestServer is part of the Microsoft.AspNetCore.TestHost package and is used for integration testing. It helps to simulate the behavior of an HTTP request within an in-memory server, making it possible to test ASP.NET Core Web API controllers without starting up an actual web server. This is useful for testing API endpoints without needing a real web server or database.

Example:

public class WeatherApiTests

{

    private readonly TestServer _server;

    private readonly HttpClient _client;

 

    public WeatherApiTests()

    {

        var webHostBuilder = new WebHostBuilder()

            .UseStartup<Startup>();  // Specify your Startup class here

        _server = new TestServer(webHostBuilder);

        _client = _server.CreateClient();

    }

 

    [Fact]

    public async Task GetWeather_ReturnsOkResponse()

    {

        // Arrange

        var request = "/weather";  // Your API endpoint

 

        // Act

        var response = await _client.GetAsync(request);

 

        // Assert

        response.EnsureSuccessStatusCode(); // Check for 200 status

        var content = await response.Content.ReadAsStringAsync();

        Assert.Contains("temperature", content);

    }

}

15. What is the purpose of InlineData in xUnit's [Theory]?

Answer:
InlineData is used in conjunction with the [Theory] attribute in xUnit to pass multiple sets of data into the same test method. It allows you to run the same test logic with different inputs to verify various scenarios.

Example:

[Theory]

[InlineData(2, 3, 5)]

[InlineData(1, 1, 2)]

[InlineData(0, 0, 0)]

public void Add_ReturnsCorrectSum(int a, int b, int expectedSum)

{

    // Arrange

    var calculator = new Calculator();

 

    // Act

    var result = calculator.Add(a, b);

 

    // Assert

    Assert.Equal(expectedSum, result);

}

16. What is the IServiceProvider and how is it used in unit testing?

Answer:
IServiceProvider is an interface in ASP.NET Core that is responsible for providing dependencies through dependency injection. It allows for the retrieval of registered services and is often used in integration tests to resolve services needed for the test.

In unit testing, you might use IServiceProvider to create a service collection and resolve dependencies manually, or you can mock the service provider to simulate the dependency resolution.

Example:

public class WeatherServiceTests

{

    private readonly ServiceProvider _serviceProvider;

 

    public WeatherServiceTests()

    {

        var services = new ServiceCollection();

        services.AddSingleton<IWeatherService, WeatherService>();

        _serviceProvider = services.BuildServiceProvider();

    }

 

    [Fact]

    public void WeatherService_ShouldReturnCorrectData()

    {

        // Arrange

        var weatherService = _serviceProvider.GetService<IWeatherService>();

 

        // Act

        var result = weatherService.GetWeather("New York");

 

        // Assert

        Assert.NotNull(result);

        Assert.Equal("New York", result.City);

    }

}

17. What is the Arrange-Act-Assert (AAA) pattern in unit testing?

Answer:
The Arrange-Act-Assert (AAA) pattern is a widely adopted methodology for writing clear and maintainable unit tests. The pattern helps organize test code by separating the setup (arrange), execution (act), and verification (assert) steps.

  • Arrange: Set up the necessary preconditions for the test (e.g., mock objects, dependencies, test data).
  • Act: Perform the action that you want to test (e.g., call the method).
  • Assert: Verify the expected outcomes (e.g., check if the returned value matches expectations, or if a method was called).

Example:

[Fact]

public void Add_ShouldReturnCorrectResult()

{

    // Arrange

    var calculator = new Calculator();

 

    // Act

    var result = calculator.Add(2, 3);

 

    // Assert

    Assert.Equal(5, result);

}

18. How do you test HTTP status codes in unit tests for Web API?

Answer:
When testing Web API controllers, you can test HTTP status codes by asserting the type of action result returned from the controller method (e.g., OkObjectResult, NotFoundResult, BadRequestObjectResult, etc.).

Example:

[Fact]

public async Task GetUser_NotFound_ReturnsNotFoundResult()

{

    // Arrange

    var mockService = new Mock<IUserService>();

    mockService.Setup(service => service.GetUserByIdAsync(It.IsAny<int>()))

               .ReturnsAsync((User)null);  // Simulate not found

 

    var controller = new UserController(mockService.Object);

 

    // Act

    var result = await controller.GetUser(1);

 

    // Assert

    var notFoundResult = Assert.IsType<NotFoundResult>(result);

    Assert.Equal(404, notFoundResult.StatusCode); // Verifying the 404 status code

}

19. How do you handle timeouts in unit tests for Web API?

Answer:
If your Web API logic has timeout-based logic (e.g., calling external APIs or services), you can simulate timeouts in unit tests using mock setups that trigger exceptions or delays. You can simulate a timeout by making the mock return a task that delays for a period or throws an exception.

Example:

[Fact]

public async Task FetchData_ShouldThrowTimeoutException_OnTimeout()

{

    // Arrange

    var mockService = new Mock<IDataService>();

    mockService.Setup(service => service.FetchDataAsync(It.IsAny<string>()))

               .ThrowsAsync(new TimeoutException("The operation timed out"));

 

    var controller = new DataController(mockService.Object);

 

    // Act & Assert

    var exception = await Assert.ThrowsAsync<TimeoutException>(() => controller.GetData("invalid"));

    Assert.Equal("The operation timed out", exception.Message);

}

20. What are "Integration Tests" in the context of Web API and how do they differ from "Unit Tests"?

Answer:

  • Integration Tests: Focus on testing the interaction between different components, such as controllers, services, and databases. They ensure that the system behaves as expected when multiple components are working together.
  • Unit Tests: Focus on testing individual components in isolation. In unit tests, dependencies are mocked to avoid actual calls to external systems (like a database or API).

Example of Integration Test:

public class WeatherControllerIntegrationTests

{

    private readonly TestServer _server;

    private readonly HttpClient _client;

 

    public WeatherControllerIntegrationTests()

    {

        var webHostBuilder = new WebHostBuilder().UseStartup<Startup>();

        _server = new TestServer(webHostBuilder);

        _client = _server.CreateClient();

    }

 

    [Fact]

    public async Task GetWeather_ReturnsCorrectStatusCode()

    {

        // Act

        var response = await _client.GetAsync("/api/weather");

 

        // Assert

        response.EnsureSuccessStatusCode();

    }

}

 

Comments

Popular posts from this blog

Multiline to singleline IN C# - CODING

EF Core interview questions for beginners

EF Core interview questions for experienced