bitplatform icon indicating copy to clipboard operation
bitplatform copied to clipboard

Unit-Testable components

Open linkdotnet opened this issue 3 years ago • 10 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Hey together,

this feature request is more a container of smaller improvements in regards to testability. Short background, I am Steven and core contributor to bUnit. I saw that you use bUnit internally to test your components. Lovely to see and great work!

Imagine a user unit testing a component which consists out of your beautiful components. He is faced with some pitfalls.

  • Is there JavaScript involved? If so, the user has to mock it or set the mock-behaviour to loose. In any case it needs manual intervention. This mainly concerns the chart because it is based on chart.js. But also "common" components like the BitDropDown uses JS calls
  • How can I trigger / click a button in bUnit? BitButton for example can have multiple representations. Either an <a href> or <button>.

Describe the solution you'd like

Multiple things can help here. Maybe a special part in your documentation highlighting how to trigger certain behaviour with for example bUnit. That should cover a lot of cases.

For the JS-Interop stuff you could offer an baseclass which does already a lot of the mocking:

public abstract class BitUITestContext : TestContext 
{
}

The main part here would be to make it convenient for all users independent if they use xUnit, nUnit or MSTest. Telerik does something similar. I just can't find their base class.

Anyway the idea is to guide the user how to unit test component which do rely on your components.

Additional context

If you need any help bUnit-wise let me know.

linkdotnet avatar Aug 02 '22 19:08 linkdotnet

@linkdotnet thanks for submitting this issue It is an interesting suggestion and I think we can discuss it with our team to have it designed and implemented. we will announce the plans or feel free to submit a PR of your own solution.

msynk avatar Aug 02 '22 19:08 msynk

Sure thing. If you need anything, just let me know ;)

linkdotnet avatar Aug 02 '22 19:08 linkdotnet

Maybe a few ideas from my side. AntBlazor has a similiar way of dealing with things. They internally have their own AntDesignTestBase. For BitPlatform "we" could introduce a similiar approach. For example a dedicated nuget package for bUnit which makes testing easier. I am not aware of any other unit testing framework for Blazor, so that should keep maintenance cost low.

Additionally one could introduce extension methods for clicking a button for example:

public class BitButtonTestExtensions
{
    public static void ClickButton(this IRenderFragment<BitButton> button)
    {
        if (button.Href is not null) 
            button.Click("a");
        else
            button.Click("button");
    }
}

Alternatively a normal extension method which sets up all the services and mocks (if needed) should be enough as well.

The user can then simply use the extensions:

// By inheriting from BitPlatformTestContext all JS is already either setup or JSRuntime is set to Loose
public class MyNiceTest : BitPlatformTestContext
{
    [Fact]
    public void ShouldDoAwesomeStuff()
    {
        var cut = RenderComponent<MyCustomComponent>();

        // Now we can use the extension method
        cut.FindComponent<BitButton>().ClickButton();

        // Assert
    }
}

Paired with a nice documentation that should cover a lot of use cases. Keep in mind that a simple documentation might be good enough for starters and if you or we from bUnit see users often time running into trouble those helpers might be useful.

Let me know your thoughts.

linkdotnet avatar Aug 04 '22 08:08 linkdotnet

@linkdotnet sry for late response, we are getting ready for a new prerelease version. interesting ideas you've got there. I'll jump in after we are done here.

msynk avatar Aug 05 '22 07:08 msynk

Nah no worries. Take your time. I was just throwing ideas around ;)

linkdotnet avatar Aug 05 '22 08:08 linkdotnet

@linkdotnet

  • about the dedicated nuget package for bUnit which makes testing easier, could you please explain it a bit?
  • the base test class is a great idea, and it would be even greater if you could submit a PR for it 😊
  • the extension method is also a good idea, lets go for it 😊

msynk avatar Aug 12 '22 09:08 msynk

Sure. Before I give explanation about the nuget package.

Base class VS Extension method

After thinking about this, I would favour an extension method over a subclass. Subclass would restrict options for the user, he can't use other base classes. Also the usage is super trivial:

using Bit.BlazorUI;

public class MyComponentTest : TestContext
{
    public MyComponentTest()
    {
        // Maybe a better name, but you get the idea
        // This method would setup all JS
        Services.AddBitPlatformUi();
    }
    
    [Fact]
    public void TestWithABitPlatformButton();
    {
        var cut = RenderComponent<MyComponent>();
  
        // Click is an extension from you... I'll show later how it works
        // This might make it easier for users, so they don't have to know if
        // the button is <button> or <a href>
        cut.FindComponent<BitButton>().Click();
    }
}

Extension:

namespace Bit.BlazorUI;

public static class RenderFragmentBaseExtensions
{
    public static void Click(this IRenderFragmentBase<BitButton> button)
    {
        ArgumentNullException.ThrowIfNull(button);

        // Only click if we don't have Href as the <a> element has no onclick event
        if (string.IsNullOrEmpty(button.Instance.Href))
            button.Find("button").Click();
   
    }
}

Nuget

Right, so there are two ways giving the user the abilities described above:

  1. Documentation - so he can copy & paste
  2. Having a separate nuget package the user can include

Of course you don't want to couple your production code with bUnit. a) you don't need it and b) you don't want to ship bUnit as dependent package to your customers in production. That is why a separate package is necessary. So having another project inside your solution which then will be published to nuget.

linkdotnet avatar Aug 12 '22 09:08 linkdotnet

@linkdotnet tnx a lot for the explanation. I do agree with the extension method approach, but adding a new project and configuring the pipeline to publish its nuget package and also the documentation is a bit too much for us atm. let me discuss it with our team and come back to you. if you have any suggestions about implementing this approach, just let me know.

msynk avatar Aug 12 '22 10:08 msynk

@linkdotnet tnx again for your contributions, and sorry for the late response. we are super busy atm 😁😭 I discussed these approaches with the team and we believe that currently, we don't have enough time/resources to handle these issues, and also our approach in these situation is using custom Code Analyzers to warn developers about their mistakes/issues which we have already done with other problems (like the async void cases). in the end, we would really appreciate it if you could take care of the desired solution(s) for these problems and let us know if you need any help to implement them. I'm going to move this issue to the V-Next milestone since we don't have time to plan them for the team in the near future. 👌✌️

msynk avatar Aug 27 '22 10:08 msynk

Don't worry. Nothing urgent and totally understandable. If I can come up with something I let you know.

Otherwise we can also wait until the first users report issues and check their feedback.

linkdotnet avatar Aug 28 '22 06:08 linkdotnet

not planned yet

msynk avatar Sep 23 '23 09:09 msynk