-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug] Fix crash and add unit test to cover the issue. #1080
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package org.wordpress.aztec.spans | |
import android.graphics.Color | ||
import android.text.TextPaint | ||
import android.text.style.CharacterStyle | ||
import androidx.annotation.VisibleForTesting | ||
import org.wordpress.aztec.AztecAttributes | ||
import org.wordpress.aztec.source.CssStyleFormatter | ||
|
||
|
@@ -25,8 +26,9 @@ class MarkSpan : CharacterStyle, IAztecInlineSpan { | |
textColorValue = safelyParseColor(colorString) | ||
} | ||
|
||
private fun safelyParseColor(colorString: String?): Int? { | ||
if (colorString == null) { | ||
@VisibleForTesting | ||
internal fun safelyParseColor(colorString: String?): Int? { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this doesn't need to be I didn't check the code further so I don't know if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think there is a misunderstanding. I marked it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I meant is that even keeping this In other words, treating the class as a black box and testing behaviors, inputs, and outputs, instead of making a specific method visible for testing and white-box testing its source code. Besides that, I think I anticipated myself a bit in my first comment mentioning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great point. And I think we may be getting into the weeds here. What I did was on purpose and I specifically meant to test just a method. When I approach unit tests I try and test a very specific unit of code. What if the implementation of one of the constructors changes? For example adding a new required parameter? The test could break making it brittle. If we test a specific method, it's independent of any business logic changes since we are testing just a function. And more importantly, we really only care about the color parsing which is what this crash is about.
With all that said, it sounds like you feel strongly about running the test a specific way so I made the changes that I think you wanted. I've never used MockK, so let me know if there are any further changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is a valid point as well! I tend to approach test with the class usage in mind, treating everything private as implementation details, which are subject to change at any time. Or as many say: "test behavior, not implementation". The testable "units" for me are any public APIs an external code can use to interact with the class. For instance, in this situation, in the app perspective, the crash happened when instantiating But what you said is totally valid as well, one might be more interested that each function inside a class work as expected, especially if they are more like scoped utility functions that are used several places inside that class. And that works fine especially in lib code (like this) and modularized projects, where Anyway, I think this was a nice discussion and I personally think the code looks cleaner now in this last iteration, so I will just reiterate my approval for this last code review. Thanks for the changes! 🙇🏼 |
||
if (colorString.isNullOrBlank()) { | ||
return null | ||
} | ||
return try { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Awesome! Thanks for adding tests! 🙇🏼 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package org.wordpress.aztec | ||
|
||
import org.junit.Assert | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.mockito.Mock | ||
import org.mockito.Mockito | ||
import org.robolectric.RobolectricTestRunner | ||
import org.wordpress.aztec.spans.MarkSpan | ||
|
||
@RunWith(RobolectricTestRunner::class) | ||
class MarkSpanTest { | ||
@Mock | ||
val markSpan = Mockito.mock(MarkSpan::class.java) | ||
/** | ||
* Test used to confirm two crashes related are fixed. | ||
* | ||
* https://github.com/wordpress-mobile/WordPress-Android/issues/20738 | ||
*/ | ||
@Test | ||
fun `Calling MarkSpan#safelyParseColor with empty string should not cause a crash`() { | ||
var error = false | ||
var result: Int? = null | ||
try { | ||
Mockito.`when`(markSpan.safelyParseColor("")).thenCallRealMethod() | ||
result = markSpan.safelyParseColor("") | ||
} catch (e: Exception) { | ||
error = true | ||
} | ||
Assert.assertFalse(error) | ||
Assert.assertEquals(null, result) | ||
} | ||
|
||
/** | ||
* Test used to confirm two crashes related are fixed. | ||
* | ||
* https://github.com/wordpress-mobile/WordPress-Android/issues/20694 | ||
*/ | ||
@Test | ||
fun `Calling MarkSpan#safelyParseColor with null string should not cause a crash`() { | ||
var error = false | ||
var result: Int? = null | ||
try { | ||
Mockito.`when`(markSpan.safelyParseColor(null)).thenCallRealMethod() | ||
result = markSpan.safelyParseColor(null) | ||
} catch (e: Exception) { | ||
error = true | ||
} | ||
Assert.assertFalse(error) | ||
Assert.assertEquals(null, result) | ||
} | ||
} | ||
thomashorta marked this conversation as resolved.
Show resolved
Hide resolved
|
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.
Suggestion: Since it's the first time adding a mocking framework to this project, I would advocate adding
MockK
, what do you think?I recently posted about Mockito issues and moving to MockK for Kotlin testing (pctCYC-1iC-p2) and the overall feedback was positive, so this feels like a nice opportunity here to avoid introducing
Mockito
in this Kotlin-heavy codebase if you're comfortable with that.