-
Notifications
You must be signed in to change notification settings - Fork 527
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
Fix #110: Filter questions required for assessment in QuestionTrainingController #227
Conversation
… training controller
@BenHenning PTAL, I have also added a json with 3 sample questions. |
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.
Thanks @vinitamurthi.
One top-level question: is this actually fixing #120? That issue appears to be closed. Is this fixing part of #110 or all of #110, instead?
Otherwise, my feedback is primarily around ensuring that we're generating this as expected. I was expecting more randomness, and it'd be good to make sure that we're testing multiple aspects of the controller.
domain/src/main/java/org/oppia/domain/exploration/ExplorationRetriever.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
Also if there is missing functionality before we can fully finish #110, what is that functionality? Can we just implement it here to consider the training controller finished? |
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.
Thanks @vinitamurthi--took another pass on this. Please let me know if you have any questions regarding my comments.
val jsonContents = assetManager.open(assetName).bufferedReader().use { it.readText() } | ||
return JSONObject(jsonContents) | ||
} | ||
} |
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.
Please add EOF newline here & elsewhere in this PR where one is missing.
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.
Done
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 appears to still be missing. Please make sure all new files have EOF newlines.
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.
Done
domain/src/main/java/org/oppia/domain/util/JsonAssetRetriever.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Outdated
Show resolved
Hide resolved
domain/src/main/java/org/oppia/domain/question/QuestionTrainingController.kt
Show resolved
Hide resolved
I have made all the changes requested, PTAL @BenHenning ! |
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.
Thanks @vinitamurthi! Did you also address my question regarding the random number generation?
Overall this PR LGTM, but my main open question is around the randomness. Shouldn't we be randomly sorting the questions so that assessments are different each time? If so, we should also be thoroughly testing these flows in a deterministic way.
"solicit_answer_details": false | ||
} | ||
] | ||
} |
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.
Nit: please add EOF newline.
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.
Done
class QuestionTrainingConstantsProvider @Inject constructor( | ||
) { | ||
fun getQuestionCountPerTrainingSession(): Int { | ||
return QUESTION_COUNT_PER_TRAINING_SESSION |
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.
Suggest providing this via Dagger instead. That would look something like:
Annotation file:
@Qualifier annotation class QuestionCountPerTrainingSession
Module:
@Module
class QuestionModule {
@Provides
@QuestionCountPerTrainingSession
fun provideQuestionCountPerTrainingSession(): Int = 10
}
When using it:
class Dependency @Inject(@QuestionCountPerTrainingSession private val int questionCountPerSession) {
...
}
This approach allows us to switch out the count in test modules to make it easier to perform testing.
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.
Done
import java.io.IOException | ||
import javax.inject.Inject | ||
|
||
/** Utility that helps retrieving JSON assets and converting them to a JSON object. */ |
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.
Nit on verb tense: Utility that retrieves JSON assets and converts them to JSON objects.
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.
Done
val jsonContents = assetManager.open(assetName).bufferedReader().use { it.readText() } | ||
return JSONObject(jsonContents) | ||
} | ||
} |
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 appears to still be missing. Please make sure all new files have EOF newlines.
class JsonAssetRetriever @Inject constructor(private val context: Context) { | ||
|
||
/** Loads the JSON string from an asset and converts it to a JSONObject */ | ||
@Throws(IOException::class) |
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.
Is this actually necessary? If not, prefer to remove since exceptions are always optional in Kotlin (this annotation should only be needed when calling this method from Java code, and we're not doing that).
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.
Removed
@Provides | ||
@Singleton | ||
fun provideQuestionTrainingConstantsProvider(): QuestionTrainingConstantsProvider { | ||
MockitoAnnotations.initMocks(this) |
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 a bit hacky and ought to be done only for test classes. However we can avoid using Mockito here altogether if you move the constant directly to the dagger graph.
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.
Got it, I have moved it to the dagger graph now
@@ -0,0 +1 @@ | |||
mock-maker-inline |
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.
Why do we need this? Prefer to remove.
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 had kept this because mockito doesnt allow mocking final classes unless you do this and all kotlin classes are final by default. But since I dont need to use mockito anymore I removed it
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.
Thanks!
import dagger.Provides | ||
import javax.inject.Qualifier | ||
|
||
/** Provider to return any constants required during the training session. */ |
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.
Perhaps this should be on the Module instead of this annotation?
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.
Done
} | ||
return trainingQuestions.take(questionCountPerSession) | ||
} | ||
|
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.
Nit: please remove extra 2 newlines.
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.
Done
val questionsDataProvider = topicController.retrieveQuestionsForSkillIds(skillIdsList) | ||
return dataProviders.transform(TRAINING_QUESTIONS_PROVIDER, questionsDataProvider) { | ||
getFilteredQuestionsForTraining( | ||
skillIdsList, it.shuffled(Random(questionTrainingSeed)), |
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.
Won't this cause the same order for subsequent assessments? I'm guessing we need to actually store the random object in a field to make sure it's shared across multiple shuffles.
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.
Yes that's right my mistake. I am storing the random object as a member variable and reusing the same object
I verified through a manual test that the random generator does send out a different assessment when called by the same object multiple times. I will submit this PR now and we can make any subsequent changes in a follow up! |
Explanation
This PR fetches a specific amount of questions, spread across each skill in the QuestionTrainingController and passes on the data provider to the QuestionAssessmentProgressController.
This also adds some fake question data with different interaction types - multiple choice, text input, and numeric input (these are the only ones that are currently supported even in the web question player) that can be used in a training session
Fixes #110
Checklist