jamiewest / signalr_core

ASP.NET Core SignalR Dart Client
https://pub.dev/packages/signalr_core
MIT License
90 stars 58 forks source link

Unit Testing Hub #66

Closed milodude closed 7 months ago

milodude commented 3 years ago

I'm facing an issue while trying to unit test my hub. I just need be able to go through the initialization of the widget without trying to make an actual http connection. The issue with provided implementation comes when going through this line

var hubConnection = HubConnectionBuilder().withUrl(hubDivisionConnectionString).build();

build() method returns a HubConnection but this is an abstract class which can not be mocked. Can someone give me a hint on how can I be able to test this?

jamiewest commented 3 years ago

We might need a MockHubConnection like the http package has. Anyone up for making a PR?

milodude commented 3 years ago

Thanks for posting a reply I'm just quite busy and completely forgot about this issue I raised. I came up with a workaround a few days ago. I had to implement a kind of startup to pass each of the services to my pages each time they are called(like a DI in c#). By doing this I was able to mock the hubBuilder since I mocked the service and then pass this while initializing the page in my test. I have a method that is called in each and every test in order to emulate a kind of "Setup" method each time a test runs. Inside of it I mocked the HubBuilder and the HubConnection necessary methods by mocking them with mockito like this

class MockHubConnection extends Mock implements HubConnection {} class MockHubBuilder extends Mock implements HubBuilder {}

void main() { final hubBuilder = MockHubBuilder(); final hc = MockHubConnection();

Widget widgetSetupToBeTested({Widget child}) { final hc = MockHubConnection(); when(hc.start()).thenAnswer((realInvocation) => Future.value()); when(hc.stop()).thenAnswer((realInvocation) => Future.value()); when(hc.onclose((exception) { })).thenAnswer((realInvocation) => Future.value()); when(hc.on(any, (arguments) { })).thenAnswer((realInvocation) => Future.value()); when(hubBuilder.hubConnection).thenAnswer((_)=>hc); return MaterialApp( home: child, navigatorObservers: [mockObserver], ); }

In the test you need to call this widgetSetupToBeTested method like this

testWidgets("test description", (tester) async { await tester.pumpWidget( widgetSetupToBeTested(child:YourPage(hubBuilder: hubBuilder))); await tester.pump(); });

And that is it. I know it might look like a difficult approach but that is the only workaround I was able to find since test at my work are a must. Any suggestions or insights would be appreaciated and if this satisfies my requirement feel free to close the ticket.

jamiewest commented 3 years ago

Thanks for the feedback, I kinda want to leave this open so I can track adding better testing support. I haven't had time to work on this lib much and a lot of my time has been spent porting the Microsoft.Extensions namespace to dart recently. I'm hoping I can return to this soon.