How to use bUnit on SfGrid with CustomAdapter

Hi, we are trying to write a set of integration tests to verify simple crud operations of an SfGrid using bUnit.

We have everything hooked up, but SfGrid is not to be invoking any operations on the CustomAdapter.

 

<SfGrid TValue="FtpDto" Toolbar="@(new List<string> { "Add", "Edit", "Delete" })">

    <SfDataManager AdaptorInstance="@typeof(FtpDataManager)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager>

    <GridColumns>

        <GridColumn Field="@(nameof(FtpDto.FTPId))" IsPrimaryKey="true" />

        <GridColumn Field="@(nameof(FtpDto.Description))" />

        <GridColumn Field="@(nameof(FtpDto.Address))" />

    </GridColumns>

    <GridEvents TValue="FtpDto" />

    <GridEditSettings Mode="EditMode.Dialog" AllowAdding="true" AllowEditing="true" AllowDeleting="true" Dialog="@EditDialogSettings">

        <Template>

            @{

                var ftp = (context as FtpDto);

                <FTPEditForm FTP="@ftp" />

            }

        </Template>

    </GridEditSettings>

</SfGrid>

public class FtpDataManager : BaseDataManager<FtpDto>

{

    public FtpDataManager(HttpClient httpClient) : base("ftp", httpClient)

    {

    }

}


public class FtpDataManager : BaseDataManager<FtpDto>

{

    public FtpDataManager(IHttpClientFactory httpClient) : base("ftp", httpClient)

    {

    }

}


public abstract class BaseDataManager<TRequest> : DataAdaptor

{

    private readonly string _controllerUrl;

    private readonly IHttpClientFactory _httpClientFactory;

    private readonly HttpClient _httpClient;


    public BaseDataManager(string controllerUrl, IHttpClientFactory httpClientFactory) : base()

    {

        _controllerUrl = controllerUrl;

        _httpClientFactory = httpClientFactory;

    }


    //[Inject]

    //public HttpClient HttpClient { get; set; }


    public override async Task<object> ReadAsync(DataManagerRequest dm, string additionalParam = null)

    {

        IEnumerable<TRequest> dataSource = await Get("Get");

        if (dm.Search != null && dm.Search.Count > 0)

        {

            // Searching

            dataSource = DataOperations.PerformSearching(dataSource, dm.Search);

        }

        if (dm.Sorted != null && dm.Sorted.Count > 0)

        {

            // Sorting

            dataSource = DataOperations.PerformSorting(dataSource, dm.Sorted);

        }

        if (dm.Where != null && dm.Where.Count > 0)

        {

            // Filtering

            dataSource = DataOperations.PerformFiltering(dataSource, dm.Where, dm.Where[0].Operator);

        }

        int count = dataSource.Count();

        if (dm.Skip != 0)

        {

            //Paging

            dataSource = DataOperations.PerformSkip(dataSource, dm.Skip);

        }

        if (dm.Take != 0)

        {

            dataSource = DataOperations.PerformTake(dataSource, dm.Take);

        }

        return dm.RequiresCounts ? new DataResult() { Result = dataSource, Count = count } : (object)dataSource;

    }


    public override async Task<object> InsertAsync(DataManager dataManager, object record, string additionalParam)

    {

        return await Post<TRequest, TRequest>(dataManager, $"AddOrUpdate", (TRequest)record);

    }


    public override async Task<object> UpdateAsync(DataManager dataManager, object record, string primaryColumnName, string additionalParam)

    {

        return await Post<TRequest, TRequest>(dataManager, $"AddOrUpdate", (TRequest)record);

    }


    public override async Task<object> RemoveAsync(DataManager dataManager, object primaryColumnValue, string primaryColumnName, string additionalParam)

    {

        string url = $"entity-api/{_controllerUrl}/{primaryColumnValue}";


        HttpResponseMessage response = await dataManager.HttpClientInstance.DeleteAsync(url);

        return await ProcessResponse<bool>(response);

    }


    private async Task<IEnumerable<TRequest>> Get(string method)

    {

        string url = $"entity-api/{_controllerUrl}/{method}";


        HttpResponseMessage response = await _httpClientFactory.CreateClient(Options.DefaultName).GetAsync(url);


        return await ProcessResponse<List<TRequest>>(response);

    }


    private async Task<TResponse> Post<TReq, TResponse>(DataManager dataManager, string method, TReq request)

    {

        string url = $"entity-api/{_controllerUrl}/{method}";


        string req = JsonSerializer.Serialize(request);


        System.Diagnostics.Debug.WriteLine(req);


        HttpResponseMessage response = await dataManager.HttpClientInstance.PostAsJsonAsync(url, request);


        return await ProcessResponse<TResponse>(response);

    }


    private static async Task<T> ProcessResponse<T>(HttpResponseMessage response)

    {

        string responseString = await response.Content.ReadAsStringAsync();

        if (response.IsSuccessStatusCode)

        {

            return JsonSerializer.Deserialize<T>(responseString);

        }


        throw ThrowException(responseString);

    }


    private static ApiException ThrowException(string responseString)

    {

        ErrorResponse errorResponse = JsonSerializer.Deserialize<ErrorResponse>(responseString);

        return new ApiException(errorResponse.Title)

        {

            Title = errorResponse.Title,

            Detail = errorResponse.Detail,

            Errors = errorResponse.Errors,

            Status = errorResponse.Status

        };

    }

}


public class FtpEditPageTest

{

    private WireMockServer _wireMockServer;


    public FtpEditPageTest()

    {

        _wireMockServer = WireMockServer.Start();

    }


    public void Dispose()

    {

        _wireMockServer.Stop();

    }


    [Fact]

    public void GetTest()

    {

        var ftpDtos = new List<FtpDto>

        {

            new FtpDto

            {

                FTPId = "Ftp",

                Description = "Test",

                Address = "localhost",

                Port = 21,

                UserName = "test",

                Password = "test",

                SSH = false,

                SSL = false,

                ImplicitSSL = false,

                ConnectionType = FTPConnectionType.Active

            }

        };


        var testContext = new TestContext();


        testContext.Services.AddOptions();

        testContext.Services.AddHttpClient(Options.DefaultName, a => a.BaseAddress = new Uri(_wireMockServer.Urls[0]));

        testContext.Services.AddScoped<FtpDataManager>();

        testContext.Services.AddSyncfusionBlazor();


        _wireMockServer.Given(Request.Create()

            .WithPath("entity-api/ftp/Get")

            .UsingGet())

        .RespondWith(Response.Create().WithBodyAsJson(ftpDtos));


        var cut = testContext.RenderComponent<FTPPage>();


        var grid = cut.FindComponent<SfGrid<FtpDto>>();

    }

}


2 Replies

NS Nick Shaw July 25, 2024 07:01 PM UTC

Following up here - we added a Task.Delay and our methods are called, we return data, but Datasource, and any data methods are all null.



PS Prathap Senthil Syncfusion Team July 26, 2024 01:24 PM UTC

Hi Nick,

Based on your query, we would like to inform you that BUnit is primarily designed for testing Blazor components and their interactions. Therefore, it is not recommended to use BUnit for SfDataManger

We suggest you try using MockTesting while using DataManager. Kindly refer the below documentation for your reference.


Reference: https://bunit.dev/docs/test-doubles/mocking-httpclient.html


We have discussed a similar query in the below forums. Kindly refer the below thread for additional information.

https://www.syncfusion.com/forums/166936/unable-to-mock-the-response-to-an-sfdatamanager

https://www.syncfusion.com/forums/159330/unit-tests


https://www.syncfusion.com/forums/186956/unit-test-a-grid

Regards,
Prathap Senthil


Loader.
Up arrow icon