如何使用FakeItEasy对WebApi控制器执行集成测试?
Hey there! Since you're new to integration testing, let's go through how to refine your current test setup and make it more robust, maintainable, and reliable—all based on the code snippets you shared.
1. Fix Configuration Management (No More Hardcoded Values!)
Right now you've got hardcoded URLs, usernames, and passwords in your test setup. That's not ideal for security or flexibility. Instead, use a configuration file (like appsettings.test.json) to store these values:
First, add an appsettings.test.json file to your test project (set "Copy to Output Directory" to "Copy if newer"):
{ "ApiSettings": { "BaseAddress": "https://mywebaaplication.com", "Username": "your-test-username", "Password": "your-test-password", "AzureAd": { "TenantId": "your-tenant-id", "ClientId": "your-client-id", "ClientSecret": "your-client-secret" } } }
Then update your Setup method to load this configuration:
using Microsoft.Extensions.Configuration; [SetUp] public void Setup() { var config = new ConfigurationBuilder() .AddJsonFile("appsettings.test.json") .Build(); _baseAddress = config["ApiSettings:BaseAddress"]; _username = config["ApiSettings:Username"]; _password = config["ApiSettings:Password"]; // Initialize AzureAD handler with config values var azureAdConfig = config.GetSection("ApiSettings:AzureAd"); var authHandler = new AzureADApiClientAuthenticationHandler( azureAdConfig["TenantId"], azureAdConfig["ClientId"], azureAdConfig["ClientSecret"] ); _apiClient = new ApiClient(authHandler, _baseAddress); }
2. Fix Test Data & Type Mismatch
In your test, you're passing customerType = 500 (an integer) but your API expects a string parameter. That'll cause a bad request! Also, using an empty customerNumber won't return meaningful results. Instead, use known test data—either pre-seed your test database with a test customer, or use a test factory to create one before the test runs.
Here's an updated test method with valid, meaningful data:
[Test] public async Task CustomersController_GetCustomer_ReturnsExpectedCustomer() { // Arrange: Pre-seed test data (use your data context or a setup script) var testCustomerNumber = "TEST-123"; var testCustomerType = "500"; // Match the string type expected by the API // Act var result = await _apiClient.GetAsync<Customer[]>($"/api/customers/GetCustomer?customerNumber={testCustomerNumber}&customerType={testCustomerType}"); // Assert Assert.IsNotNull(result); Assert.AreEqual(1, result.Length); // Expect exactly one customer for our test data Assert.AreEqual(testCustomerNumber, result[0].CustomerNumber); // Verify the correct customer is returned Assert.AreEqual(testCustomerType, result[0].CustomerType); }
3. Ensure Test Isolation
Integration tests should run independently—one test shouldn't affect another. To do this:
- Use a dedicated test database (not your production or dev DB)
- Reset the database state before each test:
- Use a tool like Respawn to truncate tables
- Wrap tests in a transaction that rolls back after execution
- Seed fresh test data in the
SetUpmethod and clean it up inTearDown
Example with transaction rollback (if using EF Core):
private IDbContextTransaction _transaction; private YourDataContext _testDbContext; [SetUp] public void Setup() { // ... existing config setup ... // Initialize test DB context _testDbContext = new YourDataContext(); _transaction = _testDbContext.Database.BeginTransaction(); // Seed test customer _testDbContext.Customers.Add(new Customer { CustomerNumber = "TEST-123", CustomerType = "500", // Set other required properties }); _testDbContext.SaveChanges(); } [TearDown] public void TearDown() { _transaction.Rollback(); // Undo all changes from the test _transaction.Dispose(); _testDbContext.Dispose(); }
4. Test Error Scenarios
Don't just test the happy path! Add tests for edge cases and errors:
- Invalid
customerNumber(should return empty array or 404) - Missing required parameters (should return 400 Bad Request)
- Unauthenticated request (should return 401 Unauthorized)
Example of an error scenario test:
[Test] public async Task CustomersController_GetCustomer_InvalidNumber_ReturnsEmptyArray() { // Act var result = await _apiClient.GetAsync<Customer[]>($"/api/customers/GetCustomer?customerNumber=INVALID-999&customerType=500"); // Assert Assert.IsNotNull(result); Assert.AreEqual(0, result.Length); }
5. Improve API Client Usage
Instead of concatenating query strings manually (which can lead to encoding issues), use HttpClient's QueryHelpers to build the request URL safely:
using System.Net.Http; var queryParams = new Dictionary<string, string> { { "customerNumber", testCustomerNumber }, { "customerType", testCustomerType } }; var requestUrl = QueryHelpers.AddQueryString("/api/customers/GetCustomer", queryParams); var result = await _apiClient.GetAsync<Customer[]>(requestUrl);
内容的提问来源于stack exchange,提问作者Ravikumar Patil

