Skip to content

Extract Purchases creation logic to factory to improve testability#543

Merged
tonidero merged 1 commit into
mainfrom
csdk-101
Jun 14, 2022
Merged

Extract Purchases creation logic to factory to improve testability#543
tonidero merged 1 commit into
mainfrom
csdk-101

Conversation

@tonidero

@tonidero tonidero commented Jun 8, 2022

Copy link
Copy Markdown
Contributor

Description

https://revenuecats.atlassian.net/browse/CSDK-101

This PR moves the creation of the Purchases object to a factory class. This allows us to test the validation logic that happens during this process. In the future, it might be good to test the whole process, but for that, we will need to create factories for the different objects that are created during this initialization process which might take a bit longer. I judged the value of that not to be that big considering there is no more logic on that part of the code aside from the validations which are already tested with these changes.

@tonidero tonidero requested a review from a team June 8, 2022 08:46
import com.revenuecat.purchases.google.BillingWrapper

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this and the only usage of this method outside this module is on the amazon features module to run a test. However, I think that test could (and probably should) be moved to the purchases module instead, which would allow to make this internal which is much preferred since it would avoid devs from using this at all. I didn't do this just yet in case I missed something, but that should be a quick change.

* @warning Only one instance of Purchases should be instantiated at a time!
*/
@Suppress("LongParameterList")
class Purchases @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal constructor(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the constructor logic outside means that this constructor needs to be internal now

proxyURL
).also {
@SuppressLint("RestrictedApi")
sharedInstance = it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This remains not tested but the logic here now is minimal. I thought about creating another configure method with a PurchasesFactory parameter so we could add tests to that, but we would have to make it visible for testing, which in turn would allow devs access to it. Considering the value of the tests here (where there is almost no logic), I thought it wasn't needed but lmk if you think otherwise

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still better than what we had before so I think it's fine!


private fun Context.hasPermission(permission: String): Boolean {
return checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about moving these to the utils.kt file in the common module, but they are only used here, so I kept them private for now.

fun setup() {
purchasesFactory = PurchasesFactory()

clearAllMocks()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed we have some tests where we don't seem to be clearing the mocks between tests, like the tests in PurchasesTest. All mocks should be isolated between tests. I added a ticket here to take a look into this: https://revenuecats.atlassian.net/browse/CSDK-111

dangerousSettings
)

val prefs = PreferenceManager.getDefaultSharedPreferences(application)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be able to test this more thoroughly, we would need to create factories for each of these dependencies. Considering there is not much more logic here, I thought the value of doing that now wasn't that big, but lmk if you think otherwise or have any other ideas.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you.

@tonidero tonidero mentioned this pull request Jun 8, 2022
3 tasks
@tonidero

Copy link
Copy Markdown
Contributor Author

Bump to this for review @aboedo @beylmk

@tonidero tonidero requested review from aboedo and beylmk June 10, 2022 16:11

@vegaro vegaro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! This was very much needed

dangerousSettings
)

val prefs = PreferenceManager.getDefaultSharedPreferences(application)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you.

@tonidero tonidero merged commit a00ef13 into main Jun 14, 2022
@tonidero tonidero deleted the csdk-101 branch June 14, 2022 14:48
@tonidero tonidero mentioned this pull request Jul 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants