Remove unneccessary abstraction
See original GitHub issueCurrently we have the following type hierarchy:
classDiagram
IRenderedFragmentBase <|-- IRenderedComponentBase
IRenderedFragmentBase <|-- IRenderedFragment
IRenderedComponentBase <|-- IRenderedComponent
IRenderedFragment <|-- RenderedFragment
RenderedFragment <|-- RenderedComponent
IRenderedComponent <|-- RenderedComponent
note for IRenderedComponent "Has no own methods.\nVirtually the same as IRenderedComponentBase"
Let’s subtract the nonpublic implementation classes for now - that leaves us still with the 4 interfaces we expose. With #1014 I started to remove one of them (the easy one).
History
The split was to anticipate things like Blazor mobile binding so that we have core types and types that are specific for the specific scenario - like mobile bindings or web.
Usage
How are those types currently used? Basically, we are offering those two types to the user depending on what he is calling
IRenderComponent<TComponent>
when we call things likeRenderComponent
so that a user has a strongly typed object that wraps his component under testIRenderedFragment
that allows wrapping an “arbitrary”RenderFragment
that doesn’t necessarily bag a “pre-defined” user component
There are two options we can go from here:
- Leave those two basic types - as they deem a good separator between those two worlds
- Morph them into something like
IRenderedComponent<TComponent?> where TComponent : IComponent
(Please note thatTComponent?
obviously isn’t a real constraint it is more about showing that the Instance behind that TComponent might benull
)
Personally, I am leaning towards the second case where we abolish literally everything and have one base type representing a component under test, independent of its content.
For that to work, all interfaces have to be merged towards bunit.core
. I am leaning out of the window and also questioning whether or not we need bunit.core
and bunit.web
. I do see the benefit for 3rd party maintainers to built upon bunit.core
but I don’t have any feeling if people really do that. (Besides they are still able even if we would merge).
Issue Analytics
- State:
- Created 7 months ago
- Comments:7 (4 by maintainers)
My biggest concern is that this is a major task, and we probably need to break it down into small pieces that can be done in a few hours, and new refactorings can be added to a todo list. Otherwise, it will end up being a thing that never gets completed.
Good summary. Thoughts:
I know of at least a few that does depend on bUnit.core. Doing so does simplify their dependency graph because it does not include AngleSharp and friends that bUnit.web has a dependency on, that’s a big plus, as far as I can tell, since bUnit.core only depends on Microsoft framework packages.
IRenderedFragmentBase
does not include theNodes
property, which would require a reference to AngleSharp. That said, perhaps mot of those that take this dependency are only depending onTestContextBase
.I am debating whether there is value in having an abstraction or just a base class, e.g. should we have an
IRenderedFragment
or aRenderedFragment
. PerhapsIRenderedFragment
keeps existing in bunit.core andRenderedFragment
with a pointer to the DOM tree is what will exist in bUnit.web.Since I only want to keep the
Render
methods around (and not the genericRenderComponent
methods), always have theRender
methods return aRenderedFragment
. We do want folks to primarily focus on testing the externally visible things, e.g. the rendered markup, and not focus on the component instance itself, so I think it’s okay to do. And we will keep theFindComponent
/FindComponents
methods around, which should returnRenderedComponent
.At the end of the day, whenever a user calls
Render
, even if they are using theRender<TComponent>(parameter builder)
variant, it is aRenderFragment
that is being rendered, wrapped inside aBunitRootComponent
, so theinstance
of aRenderedFragment
returned from aRender()
call will always point to theBunitRootComponent
.