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
Post a Comment