-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Android: Fix Cucumber execution on Gradle #1094
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
Conversation
* the connected check tasks of the Android/Gradle build system do not like non-unique test names * we add a unique index to the test names if they are non-unique (e.g. on scenario outlines with multiple examples) * for this bug fix, we provide a unit test
4e47cec
to
acb4bb5
Compare
This is very needed beacuse |
159ec4c
to
74325ea
Compare
# Conflicts: # android/src/main/java/cucumber/runtime/android/AndroidInstrumentationReporter.java # android/src/test/java/cucumber/runtime/formatter/AndroidInstrumentationReporterTest.java
* the connected check tasks of the Android/Gradle build system do not like non-unique test names * we add a unique index to the test names if they are non-unique (e.g. on scenario outlines with multiple examples) * for this bug fix, we provide a unit test This is a re-integration of PR-1094. The original pull request code was performed on 1.2.6-SNAPSHOT base. This code bases on version 2.3.2-SNAPSHOT.
@mlvandijk the code is now up-to-date again Please note, that this pull request only fixes ambiguous test names in Gradle HTML reports. For a proper Android project configuration I will provide an updated version of the Cukealator project within this pull request with the next Git push. |
…ools - Update to Android Studio 3.0.1, SDK 26+ and Gradle 4.1 - Replace Instrumentation class by CucumberRunner - CucumberRunner uses AndroidJUnitRunner (JUnit 4+) - CalculationSteps class uses ActivityTestRule instead of deprecated ActivityInstrumentationTestCase2 - Fix permissions to write reports on internal storage
* Update README.md * Enable local Maven dependencies for better development experience * Describe, how to use Cukeulator example project with locally built Cucumber-JVM
I created issue 1314 with some extra information how this pull request may be applied. Please feel free to make suggestions for improvements. Maybe some code (e.g. |
As the JUnit formatter already has a similar handling of making test cases names unique, I think we should use consistent behavior here, that is
A rational for not using a blank in the first case, and to stay away from |
…ike JUnitFormatter in cucumber-core
@brasmusson Thanks for your feedback! You are right! Changed the code right now. |
Is anyone available to review this pull request? |
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.
Unfortunately I don't use Android so cannot comment on that. Some other feedback provided below.
androidTestCompile 'io.cucumber:cucumber-android:2.3.0' | ||
// | ||
// The following dependency works, if you build Cucumber-JVM on your local machine: |
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.
Should be added to the android README instead of in comments here?
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.
@mlvandijk Thanks for your feedback
Please look at the end of README.md
There is a reference to build.gradle. I think it is better to leave the technical details in build.gradle since it does not affect most users.
.invokeGetUniqueTestNameOnDifferentStatesInTestCaseLifecycle() | ||
); | ||
|
||
// TODO Consider to split this test method into multiple ones, to fulfil the one-assert-per-test-method-paradigm |
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.
Should this be done? (or remove "TODO"). In general, PR contains a several comments that should possible either be javadoc or be removed.
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.
@mlvandijk Thanks again for your feedback
I removed the TODO comment, added/improved comments and hopefully made the test method more readable
I've made some refactoring to avoid duplicating code |
I will definitely not have time to look at it before the weekend. |
I've run all my Android tests with this PR but for 653 test cases got 648 reports. I need to investigate it further. Without this PR I have about 350 reports. |
I had 2 features with the same name and first of them was overwritten in gradle report. I'm not sure if feature name conflict should be somehow resolved by |
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 apologize for delayed review.
The behavior works, but I think that getUniqueTestName
and ensureUniqueTestName
should be made into one method, and that the test should be divided so that the test names provides specification/documentation of the behavior under test.
* More technical: Checks, if {{@link AndroidInstrumentationReporter#getUniqueTestName(TestCase)}} is working. | ||
* | ||
* Note about the test code: We are using multiple assertions and for-loops in this method, which is a code smell. | ||
* Here it is okay, since we are just answering the question if the getUniqueTestName-method is working or not. |
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'm a big fan of "Test method names should be sentences (that specify/document the item under test)" (see https://dannorth.net/introducing-bdd/), so I do not think this test is okay. The interesting behavior that should be specified/documented in test method names includes:
- test case names are made unique with numbered suffices
- the numbered suffices do not include blanks when test case names do not include blanks
- out of order identical test case names are also made unique
- running a test case several times will use the same name each time
- identical test case names in different feature will not be changed
currentTestCaseName = testCase.getName(); | ||
// Since the names of test cases are not guaranteed to be unique, we must check for unique names | ||
ensureUniqueTestName(testCase); | ||
currentTestCaseName = getUniqueTestName(testCase); |
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.
What we want to do here is to calculate the unique name for the current test case, to divide this into two methods which are dependent and need to be called in order i s IMHO not the right solution (if this is driven from "command query separation", I do not think it is the right place for it). I think getUniqueTestName
(maybe renamed calculateUniqueTestName
to indicate that it is not just a getter) should both do the work and return the result.
* @param testCase the testCase | ||
* @return the unique test name or {@code null} | ||
*/ | ||
String getUniqueTestName(TestCase testCase) { |
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.
If this method did all the work I could be okay with it being package private and all details of its behavior tested by direct calls from the test class. Currently when its only use in test is to fetch data after startTestCase
has been executed from the tests, I think it should be made private and the tests get the test names from the instrumentation (like in this test)
@@ -458,6 +464,128 @@ public void step_result_contains_only_the_current_scenarios_severest_result() { | |||
inOrder.verify(instrumentation).sendStatus(eq(StatusCodes.OK), secondCaptor.capture()); | |||
} | |||
|
|||
/** | |||
* Verifies, that different test names are used when scenario names are duplicated. | |||
* More technical: Checks, if {{@link AndroidInstrumentationReporter#getUniqueTestName(TestCase)}} is working. |
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.
Currently, the behavior tested is performed by ensureUniqueTestName
(but I'm suggesting to change that).
} | ||
|
||
// when | ||
private void invokeGetUniqueTestNameOnDifferentTestCaseStates() { |
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.
This is just confusing. The unique name is calculated once (in startTestCase
), so calling getUniqueTestName
several times during the test life cycle cannot be relevant. This is a good reason why getUniqueTestName
should be private.
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.
@brasmusson Thanks for your review. It was very helpful
I agree with your point, that my tests are too low-level, will correct it later
/** | ||
* Creates a unique test name for the given test case by filling the internal maps | ||
* {@link #uniqueTestNameForTestCase} and {@link #uniqueTestNamesForFeature}.<br/> | ||
* If the test case name is unique, it will be used, otherwise, a index will be added "(2)", "(3)", "(4)", ... |
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.
"(2)" etc, is not correct anymore.
|
||
/** | ||
* Gets the unique test name for the given test case.<br/> | ||
* If, {@link #ensureUniqueTestName(TestCase)} was not yet invoked for the test case, {@code null} will be returned. |
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.
This indicate the need to make a check for null
when calling getUniqueTestName
but it should not be used in such a way that will happen. For me it is another reason why getUniqueTestName
and ensureUniqueTestName
should be made into one method.
- Create merged method calculateUniqueTestName from getUniqueTestName and ensureUniqueTestName and make it private - Use better test method name: test_case_names_are_unique_on_equal_scenario_names (instead of scenario_outline_all_test_names_unique) - Refactor test code: now it should be readable
@brasmusson Your suggestions should be implemented now. Thanks again! The test method is still a little bit long with some for-loops, but I think that should be okay here. |
@brasmusson Can you look again at this pull request, please? |
To provide better documentation of the functionality, that is: * test names within feature are made unique by appending blank and number * test names within are made unique by appending underscore and number when no blank in name * test names in different features can be the same * test names are made unique also when not consecutive
@cgnuechtel I was not clear enough that I wanted the test case split up. I fixed that in 9b63692, now the test case names provide the documentation:
|
Hi @cgnuechtel, Thanks for your making your first contribution to Cucumber, and welcome to the Cucumber committers team! You can now push directly to this repo and all other repos under the cucumber organization! 🍾 In return for this generous offer we hope you will:
On behalf of the Cucumber core team, |
@brasmusson and @aslakhellesoy Thanks for the good news 😊 |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Fix Android test execution for Gradle builds on scenario outlines with multiple examples
Details
If you would use the current implementation of Cucumber Android with the connected-check Gradle tasks plus scenario outlines and multiple examples, not all tests will be executed. With this fix, it will be executed.
Motivation and Context
This change fixes the great Cucumber software on scenario outlines with examples.
As I know, there is no open issue for this bug fix.
How Has This Been Tested?
Automatic tests have been added.
The changes have been applied to the existing Cukeulator example project on my local machine.
Screenshots (if appropriate):
Types of changes
Checklist: