-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[In_App_Purchase] Improve testability #2016
[In_App_Purchase] Improve testability #2016
Conversation
… in a more specific method.
…chase_improve_testability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the improvement! I have a minor optional/subjective suggestion.
import com.android.billingclient.api.BillingClient; | ||
import io.flutter.plugin.common.MethodChannel; | ||
|
||
public class BillingClientFactory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this works and it's definitely an improvement over the current code. But there's some subjective style nits I have with this approach.
- It's not
final
, so it could be subclassed in unexpected ways in the future. https://stackoverflow.com/a/218761. I think we need this to be non-final for it to be mockable, which leads to... - When this is used in the test, it's mocked and then the mock is returning the other mock BillingClient. That totally works but it's usually better to use real objects whenever possible.
It adds a little extra overhead, but I'd prefer that this were an interface that the test had it's own implementation instead.
interface BillingClientFactory {
BillingClient createBillingClient(Context context, MethodChannel channel);
}
// Instantiated in InAppPurchasePlugin#registerWith
class BillingClientFactoryImpl implements BillingClientFactory {
public BillingClient createBillingClient(Context context, MethodChannel channel) {
return BillingClient.newBuilder(context)
.setListener(new PluginPurchaseListener(channel))
.build();
}
}
And then the tests could have a real implementation of this that returned the mock:
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
BillingClientFactory factory = (Context context, MethodChannel channel) -> mockBillingClient;
plugin = new InAppPurchasePlugin(factory, registrar, mockMethodChannel);
}
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all your suggestions are fair.
Mockito v2 can mock final classes! \o/
https://stackoverflow.com/a/40018295/2742962
but it comes with some overhead /o\
As we control the abstraction, let's go with the interface. :-D
@mklim |
It seems to complain about a recent change I made in the connectivity. |
@BugsBunnyBR I think the commit passed the formatting check. Could you try again after merging master, and also make sure your flutter is on master? |
This branch is even with the master branch, I also ran |
@BugsBunnyBR @cyanglaz it looks for some reason the formatting check is just failing now. We have logic to only run checks against "changed" plugins which must have failed here. Or it's possible that the formatting rules changed since the PRs were merged in. I'll submit a fix to unblock this for now. |
@BugsBunnyBR it looks like the formatter is complaining about a change it applied through you to this branch, a07f6e2. I bet the problem is the same that I had, running Edited to add: I filed flutter/flutter#39767 to make sure that the versions don't go out of sync like this. |
@mklim Thank you! Let's see if the CI likes the new commit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks again!
This PR creates a factory for BillingClient, with that was possible to remove a secondary constructor that was used just for test. With the introduction of the factory there was the need to update some tests as it was testing states that would never be reached in the normal plugin flow (due the usage of the constructor for testing). Basically, the test cases depended on the state of BillingClient that would be null if no previous setup was executed.
This PR creates a factory for BillingClient, with that was possible to remove a secondary constructor that was used just for test. With the introduction of the factory there was the need to update some tests as it was testing states that would never be reached in the normal plugin flow (due the usage of the constructor for testing). Basically, the test cases depended on the state of BillingClient that would be null if no previous setup was executed.
This PR creates a factory for BillingClient, with that was possible to remove a secondary constructor that was used just for test. With the introduction of the factory there was the need to update some tests as it was testing states that would never be reached in the normal plugin flow (due the usage of the constructor for testing). Basically, the test cases depended on the state of BillingClient that would be null if no previous setup was executed.
Description
This PR creates a factory for BillingClient, with that was possible to remove a secondary constructor that was used just for test.
With the introduction of the factory there was the need to update some tests as it was testing states that would never be reached in the normal plugin flow (due the usage of the constructor for testing). Basically, the test cases depended on the state of BillingClient that would be null if no previous setup was executed.
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze
) does not report any problems on my PR.Breaking Change
Does your PR require plugin users to manually update their apps to accommodate your change?