Skip to content

Commit 197103f

Browse files
QualityOwlQualityOwlCopilotCopilot
authored
Initial Add of the Restful Booker API Test Project (#1)
* Initial add of the Restful Booker API test project. * Fix 'run-tests.yml' build and test tasks. * Fix 'run-tests.yml' issues. * Update .github/workflows/run-tests.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Restful.Booker.Api/Restful.Booker.Api.Tests/config/appsettings.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Restful.Booker.Api/Restful.Booker.Api.slnx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Restful.Booker.Api/Restful.Booker.Api.Tests/test-data/TestData.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add copilot review instructions. * Update TestData namespace. * Make ApiSettings properties nullable. * Update test class namespaces. * Update solution file to correct test project path. * Update Restful.Booker.Api/Restful.Booker.Api.Tests/test-cases/BookingController_Tests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Restful.Booker.Api/Restful.Booker.Api.Tests/test-cases/BookingController_Tests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Restful.Booker.Api/Restful.Booker.Api.Tests/test-cases/BookingController_Tests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * add createResponse and created assertions before PUT request in UpdateBooking test Agent-Logs-Url: https://github.com/QualityOwl/demo-rest-api-tests-csharp/sessions/7331ada5-03c4-4568-a81d-83a4c51e0fee Co-authored-by: QualityOwl <75451637+QualityOwl@users.noreply.github.com> * Fix run-tests.yml permissions. --------- Co-authored-by: QualityOwl <josh@qualityowl.llc> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent e3584e0 commit 197103f

17 files changed

Lines changed: 735 additions & 0 deletions
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
description: 'Code review instructions for GitHub Copilot'
3+
applyTo: '**'
4+
excludeAgent: ["coding-agent"]
5+
---
6+
7+
## General Review Principles
8+
9+
When performing a code review, follow these principles:
10+
11+
1. **Be specific**: Reference exact lines, files, and provide concrete examples
12+
2. **Provide context**: Explain WHY something is an issue and the potential impact
13+
3. **Suggest solutions**: Show corrected code when applicable, not just what's wrong
14+
4. **Be constructive**: Focus on improving the code, not criticizing the author
15+
5. **Recognize good practices**: Acknowledge well-written code and smart solutions
16+
6. **Be pragmatic**: Not every suggestion needs immediate implementation
17+
7. **Group related comments**: Avoid multiple comments about the same topic
18+
19+
## Code Quality Standards
20+
21+
When performing a code review, check for:
22+
23+
### Clean Code
24+
- Descriptive and meaningful names for variables, methods, and classes
25+
- Single Responsibility Principle: each function/class does one thing well
26+
- DRY (Don't Repeat Yourself): no code duplication
27+
- Avoid deeply nested code (max 3-4 levels)
28+
- Avoid magic numbers and strings (use constants)
29+
- Code should be self-documenting; comments only when necessary
30+
31+
### Error Handling
32+
- Proper error handling at appropriate levels
33+
- Meaningful error messages
34+
- No silent failures or ignored exceptions
35+
- Fail fast: validate inputs early
36+
- Use appropriate error types/exceptions
37+
38+
## Security Review
39+
40+
When performing a code review, check for security issues:
41+
42+
- **Sensitive Data**: No passwords, API keys, tokens, or PII in code or logs
43+
- **Input Validation**: All user inputs are validated and sanitized
44+
- **SQL Injection**: Use parameterized queries, never string concatenation
45+
- **Authentication**: Proper authentication checks before accessing resources
46+
- **Authorization**: Verify user has permission to perform action
47+
- **Cryptography**: Use established libraries, never roll your own crypto
48+
- **Dependency Security**: Check for known vulnerabilities in dependencies
49+
50+
## Testing Standards
51+
52+
When performing a code review, verify test quality:
53+
54+
- **Coverage**: Critical paths and new functionality must have tests
55+
- **Test Names**: Descriptive names that explain what is being tested
56+
- **Test Structure**: Clear Arrange-Act-Assert or Given-When-Then pattern
57+
- **Independence**: Tests should not depend on each other or external state
58+
- **Assertions**: Use specific assertions, avoid generic assertTrue/assertFalse
59+
- **Edge Cases**: Test boundary conditions, null values, empty collections
60+
- **Mock Appropriately**: Mock external dependencies, not domain logic
61+
62+
## Architecture and Design
63+
64+
When performing a code review, verify architectural principles:
65+
66+
- **Separation of Concerns**: Clear boundaries between layers/modules
67+
- **Dependency Direction**: High-level modules don't depend on low-level details
68+
- **Interface Segregation**: Prefer small, focused interfaces
69+
- **Loose Coupling**: Components should be independently testable
70+
- **High Cohesion**: Related functionality grouped together
71+
- **Consistent Patterns**: Follow established patterns in the codebase
72+
73+
## Documentation Standards
74+
75+
When performing a code review, check documentation:
76+
77+
- **Complex Logic**: Non-obvious logic should have explanatory comments
78+
- **README Updates**: Update README when adding features or changing setup
79+
- **Breaking Changes**: Document any breaking changes clearly
80+
- **Examples**: Provide usage examples for complex features
81+
82+
## Comment Format Template
83+
84+
When performing a code review, use this format for comments:
85+
86+
```markdown
87+
**[PRIORITY] Category: Brief title**
88+
89+
Detailed description of the issue or suggestion.
90+
91+
**Why this matters:**
92+
Explanation of the impact or reason for the suggestion.
93+
94+
**Suggested fix:**
95+
[code example if applicable]
96+
97+
**Reference:** [link to relevant documentation or standard]
98+
```
99+
100+
## Review Checklist
101+
102+
When performing a code review, systematically verify:
103+
104+
### Code Quality
105+
- [ ] Code follows consistent style and conventions
106+
- [ ] Names are descriptive and follow naming conventions
107+
- [ ] Functions/methods are small and focused
108+
- [ ] No code duplication
109+
- [ ] Complex logic is broken into simpler parts
110+
- [ ] Error handling is appropriate
111+
- [ ] No commented-out code or TODO without tickets
112+
113+
### Security
114+
- [ ] No sensitive data in code or logs
115+
- [ ] Input validation on all user inputs
116+
- [ ] No SQL injection vulnerabilities
117+
- [ ] Authentication and authorization properly implemented
118+
- [ ] Dependencies are up-to-date and secure
119+
120+
### Testing
121+
- [ ] New code has appropriate test coverage
122+
- [ ] Tests are well-named and focused
123+
- [ ] Tests cover edge cases and error scenarios
124+
- [ ] Tests are independent and deterministic
125+
- [ ] No tests that always pass or are commented out
126+
127+
### Architecture
128+
- [ ] Follows established patterns and conventions
129+
- [ ] Proper separation of concerns
130+
- [ ] No architectural violations
131+
- [ ] Dependencies flow in correct direction
132+
133+
### Documentation
134+
- [ ] Complex logic has explanatory comments
135+
- [ ] README is updated if needed
136+
- [ ] Breaking changes are documented

.github/workflows/run-tests.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Run API Tests
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
actions: read
13+
checks: write
14+
15+
jobs:
16+
test:
17+
name: Run Tests
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@v4
23+
24+
- name: Setup .NET 10
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: '10.x'
28+
29+
- name: Restore NuGet
30+
run: dotnet restore Restful.Booker.Api/Restful.Booker.Api.slnx
31+
32+
- name: Build
33+
run: dotnet build Restful.Booker.Api/Restful.Booker.Api.slnx --no-restore -p:WarningLevel=0
34+
35+
- name: Run tests
36+
run: dotnet test Restful.Booker.Api/Restful.Booker.Api.slnx --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx" -p:WarningLevel=0
37+
env:
38+
ApiSettings__Authentication__Username: ${{ secrets.AUTH_USERNAME }}
39+
ApiSettings__Authentication__Password: ${{ secrets.AUTH_PASSWORD }}
40+
41+
- name: Upload test results
42+
uses: actions/upload-artifact@v4
43+
if: always()
44+
with:
45+
name: test-results
46+
path: '**/test-results.trx'
47+
48+
- name: Publish test results
49+
uses: dorny/test-reporter@v3
50+
if: always()
51+
with:
52+
name: Test Results
53+
path: '**/test-results.trx'
54+
reporter: dotnet-trx
55+
fail-on-empty: 'false'

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,6 @@ FodyWeavers.xsd
416416
*.msix
417417
*.msm
418418
*.msp
419+
420+
# Local workspace for Visual Studio Code
421+
.workspace*/*
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
<UserSecretsId>da0ddf5c-3c05-4796-95d9-939ccd8d9cd3</UserSecretsId>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="coverlet.collector" Version="8.0.1">
13+
<PrivateAssets>all</PrivateAssets>
14+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15+
</PackageReference>
16+
<PackageReference Include="FluentAssertions" Version="7.2.2" />
17+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.5" />
18+
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.5" />
19+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.5" />
20+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.5" />
21+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.5" />
22+
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.5" />
23+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
24+
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
25+
<PackageReference Include="xunit" Version="2.9.3" />
26+
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
27+
<PrivateAssets>all</PrivateAssets>
28+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
29+
</PackageReference>
30+
</ItemGroup>
31+
32+
<ItemGroup>
33+
<Using Include="Xunit" />
34+
</ItemGroup>
35+
36+
<ItemGroup>
37+
<None Update="config\appsettings.json">
38+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
39+
</None>
40+
<None Update="xunit.runner.json">
41+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
42+
</None>
43+
</ItemGroup>
44+
45+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Restful.Booker.Api.Tests.Configuration;
2+
3+
public class ApiSettings
4+
{
5+
public string? BaseUrl { get; set; }
6+
public Authentication? Authentication { get; set; }
7+
public int Timeout { get; set; }
8+
}
9+
10+
public class Authentication
11+
{
12+
public string? Username { get; set; }
13+
public string? Password { set; get; }
14+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Restful.Booker.Api.Tests.Data;
3+
4+
namespace Restful.Booker.Api.Tests.Configuration;
5+
6+
public static class TestConfiguration
7+
{
8+
private static IConfiguration? _configuration;
9+
10+
public static IConfiguration Configuration
11+
{
12+
get
13+
{
14+
if (_configuration == null)
15+
{
16+
_configuration = new ConfigurationBuilder()
17+
.SetBasePath(Directory.GetCurrentDirectory())
18+
.AddJsonFile("config/appsettings.json", optional: false, reloadOnChange: true)
19+
//.AddJsonFile("test-data/test-data.json", optional: false, reloadOnChange: true)
20+
.AddUserSecrets<ApiSettings>()
21+
.AddEnvironmentVariables()
22+
.Build();
23+
}
24+
return _configuration;
25+
}
26+
}
27+
28+
public static ApiSettings GetApiSettings()
29+
{
30+
var settings = new ApiSettings();
31+
Configuration.GetSection("ApiSettings").Bind(settings);
32+
return settings;
33+
}
34+
35+
public static TestData GetTestData()
36+
{
37+
var testData = new TestData();
38+
Configuration.GetSection("TestData").Bind(testData);
39+
return testData;
40+
}
41+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"ApiSettings": {
3+
"BaseUrl": "https://restful-booker.herokuapp.com",
4+
"Authentication": {
5+
"Username": "", // Will be overridden by environment variables in GitHub Actions
6+
"Password": "" // Will be overridden by environment variables in GitHub Actions
7+
},
8+
"Timeout": 30
9+
}
10+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Restful.Booker.Api.Tests.Configuration;
2+
using Restful.Booker.Api.Tests.Models;
3+
using Newtonsoft.Json;
4+
using System.Net.Http.Headers;
5+
using System.Text;
6+
7+
namespace Restful.Booker.Api.Tests.Fixtures;
8+
9+
public class TestFixture : IDisposable
10+
{
11+
public HttpClient HttpClient { get; }
12+
public ApiSettings Settings { get; }
13+
private string? _authToken;
14+
15+
public TestFixture()
16+
{
17+
Settings = TestConfiguration.GetApiSettings();
18+
19+
HttpClient = new HttpClient
20+
{
21+
BaseAddress = new Uri(Settings.BaseUrl),
22+
Timeout = TimeSpan.FromSeconds(Settings.Timeout)
23+
};
24+
25+
HttpClient.DefaultRequestHeaders.Accept.Add(
26+
new MediaTypeWithQualityHeaderValue("application/json"));
27+
}
28+
29+
public async Task<string> GetAuthTokenAsync()
30+
{
31+
if (!string.IsNullOrEmpty(_authToken))
32+
return _authToken;
33+
34+
var authRequest = new
35+
{
36+
username = Settings.Authentication.Username,
37+
password = Settings.Authentication.Password
38+
};
39+
40+
var content = new StringContent(
41+
JsonConvert.SerializeObject(authRequest),
42+
Encoding.UTF8,
43+
"application/json");
44+
45+
var response = await HttpClient.PostAsync("/auth", content);
46+
response.EnsureSuccessStatusCode();
47+
48+
var responseBody = await response.Content.ReadAsStringAsync();
49+
var authResponse = JsonConvert.DeserializeObject<AuthResponseDto>(responseBody);
50+
51+
_authToken = authResponse?.Token ?? throw new InvalidOperationException("Failed to obtain auth token");
52+
return _authToken;
53+
}
54+
55+
public void Dispose()
56+
{
57+
HttpClient?.Dispose();
58+
GC.SuppressFinalize(this);
59+
}
60+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Newtonsoft.Json;
2+
3+
namespace Restful.Booker.Api.Tests.Models;
4+
5+
public class AuthResponseDto
6+
{
7+
[JsonProperty("token")]
8+
public string Token { get; set; } = string.Empty;
9+
}

0 commit comments

Comments
 (0)