# NUnit

前情提要

以下範例是 .NET Core 6.0.0 的範例

需要額外下載套件

Moq (用來做 mockito 的相關行為)

FluentAssertions (用來提升可讀性)

### 單元測試

#### 硬斷言

```
[Test]
public void Hard_Assertion()
{
    // Arrange
    string str = "123";
    string expected = "2";

    // Act
    string actual = str.Substring(1, 1);

    // Assert
    // 原生寫法
    Assert.AreEqual(actual, expected);
    // 使用 FluentAssertions 提升可讀性
    actual.Should().Be(expected);
}
```

#### 軟斷言

```
[Test]
public void Soft_Assertion()
{
    // Arrange
    string str = "123";

    // Act
    string actual1 = str.Substring(1, 1);
    string actual2 = str.Substring(1, 2);

    // Assert
    // 原生寫法
    Assert.Multiple(() =>
    {
        Assert.AreEqual("2",actual1);
        Assert.AreEqual("23",actual2);
    });
    // 使用 FluentAssertions 提升可讀性
    using (new AssertionScope())
    {
        actual1.Should().Be("2");
        actual2.Should().Be("23");
    }
}
```

#### 驗證 Exception

```
[Test]
public void Throwing_Exception()
{
    // Arrange

    // 原生寫法
    // Act
    var ex = Assert.Throws<Exception>(()=>throwException());
    // Assert
    Assert.That(ex.Message, Does.Contain("Magic"));

    // 使用 FluentAssertions 提升可讀性
    // Act
    Action actual = () => throwException();
    // Assert
    actual.Should().Throw<Exception>().WithMessage("*Magic*");
}

private void throwException()
{
    throw new Exception("Magic");
}
```

API 測試

參考資料:(<https://www.ruyut.com/2023/04/nunit-aspnet-core6-api-integration-testing.html>)

\*還有重構空間，此處僅是API測試的範例，可讀性方面請參考單元測試部分

```
using System.Text;
using Microsoft.AspNetCore.Mvc.Testing;
using Newtonsoft.Json;
using JsonSerializer = System.Text.Json.JsonSerializer;

namespace {namespace};

public class {controllerName}Test
{
    private WebApplicationFactory<Program> _factory = null!;
    private HttpClient _client = null!;

    [OneTimeSetUp]
    public void Init()
    {
        _factory = new WebApplicationFactory<Program>();
        _client = _factory.CreateClient();
        // 這行會切正式環境，拿掉就是測試環境 Debugger
        // Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT","Production"); //正式環境
        Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development"); //測試環境
    }

    [OneTimeTearDown]
    public void Cleanup()
    {
        _factory.Dispose();
    }

    [Test]
    public async Task {MethodName}_{type}()
    {
        // Arrange
        var type = "keyWord";
        string id= "id";
        var url = $"url{type}?id={id}";

        // Act
        var response = await WhenGet<JsonResultBase>(url);

        // Assert
        ShouldBeSuccessHasData(response);
        {MethodName}ResponseShouldBe(response!.data);
    }
    
    [Test]
    public async Task {MethodName}_{type}()
    {
        // Arrange
        var type = "keyword2";
        string id= "id";
        string day = "1";
        var url = $"url{type}?id={id}&day={day}";

        // Act
        var response = await WhenGet<JsonResultBase>(url);

        // Assert
        ShouldBeSuccessHasData(response);
        {MethodName}ResponseShouldBe(response!.data);
    }
    
    [Test]
    public async Task {MethodName}_{type}_shouldBeNull()
    {
        // Arrange
        var type = "type";
        string id= "id";
        var url = $"url{type}?id={id}&day={day}";

        // Act
        var response = await WhenGet<JsonResultBase>(url);

        // Assert
        ShouldBeSuccessHasData(response);
        {MethodName}ResponseShouldBeNull(response!.data);
    }

    private async Task<T?> WhenGet<T>(string url)
    {
        var response = await _client.GetAsync(url);
        var content = await response.Content.ReadAsStringAsync();
        //Console.Out.WriteLine(content);
        T? responseBase = JsonConvert.DeserializeObject<T>(content);
        return responseBase;
    }

    private static void ShouldBeSuccessHasData(JsonResultBase? responseBase)
    {
        Assert.IsTrue(responseBase.success);
        Assert.IsNull(responseBase.message);
        Assert.IsNotNull(responseBase.data);
    }
    
    private static void ShouldBeSuccessHasNoData(JsonResultBase? responseBase)
    {
        Assert.IsTrue(responseBase.success);
        Assert.IsNull(responseBase.message);
        Assert.IsNull(responseBase.data);
    }

    private static void {MethodName}ResponseShouldBe(object obj)
    {
        {responseClass}? data =
            JsonConvert.DeserializeObject<{responseClass}>(JsonConvert.SerializeObject(obj));
        Assert.IsNotNull(data.Content);
        Assert.IsNotNull(data.ContentFileInfo);
        Assert.IsNotNull(data.ContentFileInfo);
        Assert.IsNotNull(data.ContentFileInfo[0].type);
        Assert.IsNotNull(data.ContentFileInfo[0].files);
        Assert.IsNotNull(data.ContentFileInfo[0].files[0].id);
        Assert.IsNotNull(data.ContentFileInfo[0].files[0].fileName);
        Assert.IsNotNull(data.ContentFileInfo[0].files[0].base64);
    }
    
    private static void {MethodName}ResponseShouldBeNull(object obj)
    {
        {responseClass}? data =
            JsonConvert.DeserializeObject<{responseClass}>(JsonConvert.SerializeObject(obj));
        Assert.IsNotNull(data);
        Assert.IsNull(data.Content);
        Assert.IsNull(data.ContentFileInfo);
    }

    [Test]
    public async Task {MethodName}_TravelNotes()
    {
        // Arrange
        var url = $"url";
        var user = Given{MethodName}Param("TravelNotes", 229, 0);
        var body = new StringContent(JsonSerializer.Serialize(user), Encoding.UTF8, "application/json");

        GivenAuthToken("token");

        // Act
        var response = await WhenPost(url, body);

        // Assert
        ShouldBeSuccessHasNoData(response);
    }
    
    [Test]
    public async Task {MethodName}_TravelPlan()
    {
        // Arrange
        var url = $"url";
        var user = Given{MethodName}Param("TravelPlan", 229, 1);
        var body = new StringContent(JsonSerializer.Serialize(user), Encoding.UTF8, "application/json");

        GivenAuthToken("token");
        
        // Act
        var response = await WhenPost(url, body);

        // Assert
        ShouldBeSuccessHasNoData(response);
    }

    private async Task<JsonResultBase?> WhenPost(string url, StringContent body)
    {
        var response = await _client.PostAsync(url, body);
        var content = await response.Content.ReadAsStringAsync();
        //Console.Out.WriteLine(content);
        JsonResultBase? responseBase = JsonConvert.DeserializeObject<JsonResultBase>(content);
        return responseBase;
    }

    private void GivenAuthToken(string token)
    {
        _client.DefaultRequestHeaders.Authorization =
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }

    private static RequestClass Given{MethodName}Param(string type, int? id, int? day)
    {
        var data = new RequestClass();
        data.Type = type;
        data.Param = new Param() { Id= id, Day = day };
        data.ContentFileInfo = new List<string>();
        return data;
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://brianwu.gitbook.io/brian/test/nunit.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
