I have a ThreadActivity with two functions, saveContacts and loadContacts. They both use sharedpreferences and Gson to save an ArrayList consisting of Objects called SimpleContacts. Somehow it cannot retrieve data from sharedpreferences once I start the Activity from somewhere else. (I tried loading instantly after saving and that works, but not if I close the Activity and re-open it)
The save function:
private fun saveContact() {
val gson = Gson()
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
try {
val editor = sharedPreferences.edit()
val json = gson.toJson(participants)
editor.putString(threadId.toString()+"_Contact", json)
editor.apply()
} catch(e: Exception) {
e.printStackTrace()
}
}
The load function:
private fun loadContact() {
val gson = Gson()
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
val type = object : TypeToken<ArrayList<SimpleContact?>?>() {}.type
try {
val json = sharedPreferences.getString(threadId.toString()+"_Contact", "")
participants = gson.fromJson(json, type)
} catch(e: Exception) {
e.printStackTrace()
}
}
I have 2 Activities that can open this ThreadActivity, if I start it from the same one, it all works perfectly fine. But when I use the other Activity to start it, the sharedPrefs are empty.
Launch Activity that works (I don't know if its because its the way the Intent is build so I will write them both here):
private fun launchThreadActivity(phoneNumber: String, name: String) {
hideKeyboard()
val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: ""
val numbers = phoneNumber.split(";").toSet()
val number = if (numbers.size == 1) phoneNumber else Gson().toJson(numbers)
Intent(this, ThreadActivity::class.java).apply {
putExtra(THREAD_ID, getThreadId(numbers))
putExtra(THREAD_TITLE, name)
putExtra(THREAD_TEXT, text)
putExtra(THREAD_NUMBER, number)
if (intent.action == Intent.ACTION_SEND && intent.extras?.containsKey(Intent.EXTRA_STREAM) == true) {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
putExtra(THREAD_ATTACHMENT_URI, uri?.toString())
} else if (intent.action == Intent.ACTION_SEND_MULTIPLE && intent.extras?.containsKey(Intent.EXTRA_STREAM) == true) {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
putExtra(THREAD_ATTACHMENT_URIS, uris)
}
startActivity(this)
}
}
Start Activity that does not work:
Intent(this, ThreadActivity::class.java).apply {
putExtra(THREAD_ID, (it as Conversation).threadId)
putExtra(THREAD_TITLE, it.title)
putExtra("fromMain", true)
startActivity(this)
}
Nevermind, it was my mistake.
When saveContact was called the threadId was not initialized yet. So basically the keys were always different.
Related
inside MainActivity I have snapShot listener to document added that calls a function inside a fragment that supose to set and update the adapter of item that stored in fire store
mFireStore.collection(Constans.BOARDS)
.whereArrayContains(Constans.ASSIGNED_TO,FireStore().getCurrentUid())
.orderBy("timeStamp", Query.Direction.DESCENDING)
.addSnapshotListener { value, e ->
Log.d("MainActivity","board listener")
if (e != null) {
Log.w(ContentValues.TAG, "Listen failed.", e)
return#addSnapshotListener
}
val boards = ArrayList<Board>()
Constans.BOARDS_CHATS_LIST = ArrayList()
for (doc in value!!) {
val board = doc.toObject(Board()::class.java)
Constans.BOARDS_CHATS_LIST.add(board)
}
fragment_chat().updateBoardToUi(Constans.BOARDS_CHATS_LIST)
}
and here is the function
fun updateBoardToUi(boardsChatsList: ArrayList<Board>) {
if(boardsChatsList.size > 0){
val context = getContext() ?: return
Log.e("${Constans.BOARDS_CHATS_LIST.size.toString()}","updateBoardToUi")
view?.rv_chats_list?.visibility = View.VISIBLE
view?.no_chats_avlible?.visibility = View.GONE
view?.rv_chats_list?.layoutManager = LinearLayoutManager(context)
view?.rv_chats_list?.setHasFixedSize(true)
//might be an error
adapter = BoardItemsAdapter(context,Constans.BOARDS_CHATS_LIST)
view?.rv_chats_list?.adapter = adapter
adapter.notifyItemInserted(0)
adapter.setOnClickListener(
object :BoardItemsAdapter.OnClickListener{
override fun onClick(position: Int, model: Board) {
Log.i("fragment chat", "on click")
val intent = Intent(context, ChatActivity::class.java)
intent.putExtra(Constans.BOARD_CHAT_DETAILS, model)
intent.putExtra("uid", FirebaseAuth.getInstance().currentUser?.uid )
intent.putExtra(Constans.DOCUMENT_ID, model.documentId)
intent.putExtra("position", position)
startActivity(intent)
}
}
)
}else{
Log.e("inside","updateBoardToUi2")
view?.no_chats_avlible?.visibility = View.VISIBLE
}
}
but the adapter deas not show the new item added even thogh I use adapter.notifyItemInserted(0)
It is because you can not hold and send data with "Constants.BOARDS_CHATS_LIST". Because every time you want to call it, it will return the default value it has. You can do 4 things that come into my mind:
1- Send the data from activity to fragment via Shared Preferences. I do not recommend this method.
2 - Send data from activity to fragment via bundle. This is doable but i do not prefer it.
3 - Move your firestore function to the fragment and declare a global list and put the records there, then use it in updateBoardToUi function. You can do this but if you need this function in other fragment, you need to copy and paste it there too.
4- You can create a new class for firestore functions, and whenever you need it, call it from there. This is the best way and i will try to help you with it.
Create new kotlin class and paste this inside it. You will later call this inside onViewCreated of your fragment, and it will send the array to the updateBoardToUi method.
class FirestoreClass {
private val mFireStore = FirebaseFirestore.getInstance()
private val mFirebaseAuth = FirebaseAuth.getInstance()
fun getBoards(fragment: YourFragmentName) {
mFireStore.collection(Constans.BOARDS)
.whereArrayContains(Constans.ASSIGNED_TO,getCurrentUserID())
.orderBy("timeStamp", Query.Direction.DESCENDING)
.addSnapshotListener { value, e ->
if (e != null) {
Log.w(ContentValues.TAG, "Listen failed.", e)
return#addSnapshotListener
}
val boards = ArrayList<Board>()
for (doc in value!!) {
val board = doc.toObject(Board()::class.java)
boards.add(board)
}
fragment.updateBoardToUi(boards)
}
}
fun getCurrentUserID(): String {
val currentUser = mFirebaseAuth.currentUser
var currentUserID = ""
if (currentUser != null) {
currentUserID = currentUser.uid
}
return currentUserID
}
}
Now we will use the list from your db.
fun updateBoardToUi(boardsChatsList: ArrayList<Board>) {
// fragment.updateBoardToUi(boards) that sent the data and now
// it is in boardsChatsList, you will use this.
if(boardsChatsList.size > 0){
val context = getContext() ?: return
Log.e("${boardsChatsList.size.toString()}","updateBoardToUi")
view?.rv_chats_list?.visibility = View.VISIBLE
view?.no_chats_avlible?.visibility = View.GONE
adapter = BoardItemsAdapter(context,boardsChatsList)
view?.rv_chats_list?.adapter = adapter
view?.rv_chats_list?.layoutManager = LinearLayoutManager(context)
view?.rv_chats_list?.setHasFixedSize(true)
adapter.setOnClickListener(
object :BoardItemsAdapter.OnClickListener{
override fun onClick(position: Int, model: Board) {
Log.i("fragment chat", "on click")
val intent = Intent(context,ChatActivity::class.java)
intent.putExtra(Constans.BOARD_CHAT_DETAILS, model)
intent.putExtra("uid", FirestoreClass().getCurrentUserID())
intent.putExtra(Constans.DOCUMENT_ID, model.documentId)
intent.putExtra("position", position)
startActivity(intent)
}
}
)
}else{
Log.e("inside","updateBoardToUi2")
view?.no_chats_avlible?.visibility = View.VISIBLE
}
}
And finally call that db function in your fragment's onViewCreated to activate all of this. If you do not have onViewCreated just paste this code:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
FirestoreClass().getUsersList(this)
}
All of this can be too much, but this is the best practice. If you learn this convention, you will easily adapt working anywhere.
I have a data class for data that come from user entries. İt is carrying this data to Firebase. This data class also includes documentId variable which is a empty string by default. I want to add document Id's that Firebase created automatically. I tried every way I could think of. But it takes default value in any way.
Here are the four code snippets about this issue. Data class, adding data activity, and retrieving data activity and their View Models.
Dataclass:
data class AnalyzeModel(
var concept: String?="",
var reason: String?="",
var result: String?="",
var rrRatio: Double?=0.0,
var tarih: Timestamp=Timestamp.now(),
var tradingViewUrl: String="",
var id : String="")
AddAnalyzeActivity, addData function:
fun addData(view: View) {
val tarih = com.google.firebase.Timestamp.now()
val rr = rrText.text.toString()
var doubleRR = rr.toDoubleOrNull()
if (doubleRR == null) { doubleRR = 0.0 }
val analyzeDTO = AnalyzeModel(
conceptText.text.toString(),
reasonForText.text.toString(),
resultAddingText.text.toString(),
doubleRR,
tarih,
chartImage.text.toString()
)
viewModel.save(analyzeDTO)
val intent = Intent(this, PairDetailActivity::class.java)
startActivity(intent)
finish()
}
AddAnalyze ViewModel, save function:
fun save(data: AnalyzeModel) {
database.collection(dbCollection!!).document("Specified").collection("Pairs")
.document(chosenPair!!)
.collection("Analysis")
.add(data)
.addOnFailureListener { exception ->
exception.printStackTrace()
Toast.makeText(getApplication(), exception.localizedMessage, Toast.LENGTH_LONG).show()
}
}
PairViewModel, retrieveData function:
private fun retrieveData() {
val docRef = collectionRef.orderBy("tarih", Query.Direction.DESCENDING)
docRef.addSnapshotListener { value, error ->
try {
if (value != null && !value.isEmpty) {
val allAnalysis= ArrayList<AnalyzeModel>()
val documents = value.documents
documents.forEach {
val analyze = it.toObject(AnalyzeModel::class.java)
if (analyze!=null){
allAnalysis.add(analyze)
}
}
list.value = allAnalysis
} else if (error != null) {
Toast.makeText(Application(), error.localizedMessage, Toast.LENGTH_LONG).show()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
I want to add document IDs that Firebase created automatically.
To solve this, you only need to annotate the field with #DocumentId.
data class AnalyzeModel(
var concept: String?="",
var reason: String?="",
var result: String?="",
var rrRatio: Double?=0.0,
var tarih: Timestamp=Timestamp.now(),
var tradingViewUrl: String="",
#DocumentId 👈
var id : String=""
)
Be also sure to have the latest version of Firestore.
Hello I am trying to retrieve url, shared from another app and toast it as well as open it in WebViewTab.
But instead id of the app is displayed in toast.
here is my code:
val extras = intent.extras
if (extras != null) {
for (key in activity.intent.extras!!.keySet()) {
CopyKey = key
val value: String? = activity.intent.extras!!.getString(CopyKey)
Toast.makeText(applicationContext, value, Toast.LENGTH_LONG).show()
TabInfo.addTab(value.toString())
}
val url = intent.extras!!.getString("query")
if (url.toString().startsWith("http")) {
TabInfo.addTab(url.toString())
intent.removeExtra("query")
}
}
Thanks in advance
This solved my issue:
val extras = intent.extras
if (extras != null) {
val externalUrl: Uri? = intent?.data //retrieves the shared text from another app.
val url = intent.extras!!.getString("query")
if (url.toString().startsWith("http")) {
TabInfo.addTab(url.toString())
intent.removeExtra("query")
}
else {
TabInfo.addTab(externalUrl.toString())
}
}
Check the detail below code snippets
Note:
Error handling & data null check can be handled separately.
Assuming success case.
val URL_FINDER_REGEX = "((http:\\/\\/|https:\\/\\/|ftp:\\/\\/|file:\\/\\/)?(www.)?(([a-zA-Z0-9-]){2,2083}\\.){1,4}([a-zA-Z]){2,6}(\\/(([a-zA-Z-_\\/\\.0-9#:?=&;,]){0,2083})?){0,2083}?[^ \\n]*)"
fun test(intent: Intent?) {
intent?.let {
it.extras?.let { extras ->
val urlQuery = extras.getString("query")
urlQuery?.let {
val links = getUrlsFromText(urlQuery)
println(links)
// TODO("Your Business logic")
}
}
}
}
fun getUrlsFromText(text: String): ArrayList<URI> {
val availableLinks = ArrayList<URI>()
val matcher: Matcher = Pattern.compile(URL_FINDER_REGEX, Pattern.CASE_INSENSITIVE).matcher(text)
while (matcher.find()) {
try {
val url = URI(matcher.group())
availableLinks.add(url)
} catch (e: Exception) {
println(e)
}
}
return availableLinks
}
This is similar to some old queries.
Ref.
Regular expression to find URLs within a string
Detect and extract url from a string?
I am trying to update the value in the First activity. For this. I have passed parameters from first Activity to second with intent and update text input. Now I want to pass the updated value to the first Activity and update the specific value. I try to send data inside saveButton onClick with setResult() method. And get value in FirstActivity with onActivityResult() method. But it does not update the value. Can you please check where I did a mistake?
First Activity
class ShowProfileActivity : AppCompatActivity() {
private lateinit var fullnameTv: TextView
private lateinit var nicknameTv: TextView
private lateinit var locationTv: TextView
private lateinit var emailTv: TextView
private lateinit var bioTv: TextView
// todo load from sp
private val mockUser: User? = User("TestName", "test", "test#gmail.com", "Italy", "this is a mocked bio")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_show_profile)
fullnameTv = findViewById(R.id.asp_user_name_tv)
nicknameTv = findViewById(R.id.asp_user_nickname_tv)
locationTv = findViewById(R.id.asp_user_location_tv)
emailTv = findViewById(R.id.asp_user_email_tv)
bioTv = findViewById(R.id.asp_user_bio_tv)
// init views with user data
fullnameTv.text = mockUser?.fullname
nicknameTv.text = mockUser?.nickname
locationTv.text = mockUser?.location
emailTv.text = mockUser?.email
bioTv.text = mockUser?.bio
var editButton = findViewById<ImageButton>(R.id.editBtn);
editButton.setOnClickListener {
editProfile();
}
}
fun editProfile() {
val intent = Intent(this#ShowProfileActivity,EditProfileActivity::class.java)
if (mockUser != null) {
intent.putExtra("group23.lab1.user_fullname", mockUser.fullname)
intent.putExtra("group23.lab1.user_nickname", mockUser.nickname)
intent.putExtra("group23.lab1.user_location", mockUser.location)
intent.putExtra("group23.lab1.user_email", mockUser.email)
intent.putExtra("group23.lab1.user_bio", mockUser.bio)
}
startActivityForResult(intent, 1)
startActivity(intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK){
if (data != null) {
if (mockUser != null) {
mockUser.fullname= data.getStringExtra("group23.lab1.user_fullname").toString() //not updated
}
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.show_profile_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_show_profile_edit -> {
/*
TODO start edit profile activity (check activity name)
val intent = Intent(this, com.group23.lab1.EditProfileActivity::class.java).apply {
if (mockUser != null) {
putExtra("group23.lab1.user_fullname", mockUser.fullname)
putExtra("group23.lab1.user_nickname", mockUser.nickname)
putExtra("group23.lab1.user_location", mockUser.location)
putExtra("group23.lab1.user_email", mockUser.email)
putExtra("group23.lab1.user_bio", mockUser.bio)
}
}
startActivityForResult(intent)
*/
Toast.makeText(this, "OPEN EDIT PROFILE", Toast.LENGTH_SHORT).show()
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
Second Activity
class EditProfileActivity : AppCompatActivity() {
private lateinit var fullnameTv: TextView
private lateinit var nicknameTv: TextView
private lateinit var locationTv: TextView
private lateinit var emailTv: TextView
private lateinit var bioTv: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_profile)
val intent = intent
fullnameTv = findViewById(R.id.asp_user_name_tv)
nicknameTv = findViewById(R.id.asp_user_nickname_tv)
locationTv = findViewById(R.id.asp_user_location_tv)
emailTv = findViewById(R.id.asp_user_email_tv)
bioTv = findViewById(R.id.asp_user_bio_tv)
// ageTv = findViewById(R.id.asp_user_age_tv)
fullnameTv.text = intent.getStringExtra("group23.lab1.user_fullname")
nicknameTv.text = intent.getStringExtra("group23.lab1.user_nickname")
locationTv.text = intent.getStringExtra("group23.lab1.user_location")
emailTv.text = intent.getStringExtra("group23.lab1.user_email")
bioTv.text = intent.getStringExtra("group23.lab1.user_bio")
var sharedPreferences = getSharedPreferences("SHARED_PREF", Context.MODE_PRIVATE)
var editor = sharedPreferences.edit()
var saveButton = findViewById<Button>(R.id.btnSave)
val name = sharedPreferences.getString("group23.lab1.user_fullname", null)
val nickName = sharedPreferences.getString("group23.lab1.user_nickname", null)
val location = sharedPreferences.getString("group23.lab1.user_location", null)
val email = sharedPreferences.getString("group23.lab1.user_emai", null)
val bio = sharedPreferences.getString("group23.lab1.user_bio", null)
fullnameTv.text = name
nicknameTv.text = nickName
locationTv.text = location
emailTv.text = email
bioTv.text = bio
saveButton.setOnClickListener {
val name = fullnameTv.text.toString()
val nickName = nicknameTv.text.toString()
val location = locationTv.text.toString()
val email = emailTv.text.toString()
val bio = bioTv.text.toString()
// var age = ageTv.text.toString()
editor.apply {
putString("group23.lab1.user_fullname", name)
putString("group23.lab1.user_nickname", nickName)
putString("group23.lab1.user_location", location)
putString("group23.lab1.user_email", email)
putString("group23.lab1.user_bio", bio)
apply();
setResult(RESULT_OK, intent);
finish();
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.show_profile_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_show_profile_edit -> {
Toast.makeText(this, "OPEN EDIT PROFILE", Toast.LENGTH_SHORT).show()
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
You start your activity 2 times:
startActivityForResult(intent, 1)
startActivity(intent)
The crux of your problem is that you're passing back the second activity's original intent, which has the original values that came from the first activity. You need to pass back a new intent with new data.
// Return a NEW intent with NEW data, not this Activity's current intent
val resultIntent = Intent().putString("group23.lab1.user_fullname", name)
setResult(RESULT_OK, resultIntent);
Beyond that, here's a few unsolicited suggestions:
1 - Remove redundant startForActivity:
startActivityForResult(intent, 1)
startActivity(intent) // <- Delete this
2 - Check for the same intent code in onActivityResult. This ensures you're handling the correct result. Doesn't matter in your case as you only have one result, but it's good to build that habit and be correct. So since you started with requestCode 1, check for that same value in the result:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK && requestCode == 1) { // Check for same request code
if (data != null) {
if (mockUser != null) {
mockUser.fullname= data.getStringExtra("group23.lab1.user_fullname").toString() //not updated
}
}
}
}
3 - Saving a local val named "intent" to shadow the activity's own "intent" property is redundant.
val intent = intent // Delete this - it's pointless
4 - You are setting values in the second activity twice - from the intent and then overwriting that with shared preferences. Pick one.
// Setting values here from Intent ...
fullnameTv.text = intent.getStringExtra("group23.lab1.user_fullname")
nicknameTv.text = intent.getStringExtra("group23.lab1.user_nickname")
locationTv.text = intent.getStringExtra("group23.lab1.user_location")
emailTv.text = intent.getStringExtra("group23.lab1.user_email")
bioTv.text = intent.getStringExtra("group23.lab1.user_bio")
var sharedPreferences = getSharedPreferences("SHARED_PREF", Context.MODE_PRIVATE)
var editor = sharedPreferences.edit()
var saveButton = findViewById<Button>(R.id.btnSave)
val name = sharedPreferences.getString("group23.lab1.user_fullname", null)
val nickName = sharedPreferences.getString("group23.lab1.user_nickname", null)
val location = sharedPreferences.getString("group23.lab1.user_location", null)
val email = sharedPreferences.getString("group23.lab1.user_emai", null)
val bio = sharedPreferences.getString("group23.lab1.user_bio", null)
// ... get completely overwritten here ... so setting them above is pointless
fullnameTv.text = name
nicknameTv.text = nickName
locationTv.text = location
emailTv.text = email
bioTv.text = bio
5 - Related to the above, you seem to be mixing and matching intents and shared preferences. Unless you actually need this data to persist to disk as "preferences", you should remove the shared preferences logic which is confusing things. On the other hand, if you do need to persist the data, then you can remove the passing of data via intents, as it ends up being redundant.
For example, your activity result could read from the shared preferences instead:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK && requestCode == 1) { // Check for same request code
if (mockUser != null) {
var sharedPreferences = getSharedPreferences("SHARED_PREF", Context.MODE_PRIVATE)
mockUser.fullname= sharedPreferences.getString("group23.lab1.user_fullname", "")
}
}
}
Please note that if you chose to use preferences, you should use Editor.commit() which is synchronous instead of Editor.apply() which is asynchronous, to ensure you values are ready to be read immediately by the next activity.
I need to write test case for the switch condition in kotlin.
Class.kt
fun getEnvSwitchURL(applicationContext: Context, envSwitchInfo: String): String {
val resources = applicationContext.getResources()
val assetManager = resources.getAssets()
val properties = Properties()
try {
val inputStream = assetManager.open("configuration.properties")
properties.load(inputStream)
val urlPref = applicationContext.getSharedPreferences(SELECTED_ENV, Context.MODE_PRIVATE)
val editor = urlPref.edit()
when (envSwitchInfo) {
"Production" ->{
editor.putString("selectedUrl", properties.getProperty("prodUrl"))
editor.apply()
selectedUrl=properties.getProperty("prodUrl")
}
"Development" ->{
editor.putString("selectedUrl", properties.getProperty("devUrl"))
editor.apply()
selectedUrl=properties.getProperty("devUrl")
}
"Testing" ->{
editor.putString("selectedUrl", properties.getProperty("testUrl"))
editor.apply()
selectedUrl=properties.getProperty("testUrl")
}
}
inputStream.close()
}
return selectedUrl
}
test.kt
#BeforeEach
fun runBeforeTest() {
testApplicationContext = Mockito.mock(Context::class.java)
testResource = Mockito.mock(Resources::class.java)
testAsset = Mockito.mock(AssetManager::class.java)
testInputStream = Mockito.mock(InputStream::class.java)
testSharedPref=Mockito.mock(SharedPreferences::class.java)
testEditor=Mockito.mock(SharedPreferences.Editor::class.java)
testProperties=Mockito.mock(Properties::class.java)
testProperties.setProperty("prodUrl", "Value");
}
#Test
fun getEnvSwitchURL() {
Mockito.`when`(testApplicationContext.getResources()).thenReturn(testResource)
Mockito.`when`(testResource.assets).thenReturn(testAsset)
Mockito.`when`(testAsset.open(Mockito.anyString())).thenReturn(testInputStream)
PowerMockito.whenNew(Properties::class.java).withNoArguments().thenReturn(testProperties)
Mockito.doNothing().`when`(testProperties).load(Mockito.any(InputStream::class.java))
Mockito.`when`(testApplicationContext.getSharedPreferences(anyString(),anyInt())).thenReturn(testSharedPref)
Mockito.`when`(testSharedPref.edit()).thenReturn(testEditor)
envSwitchUtils.getEnvSwitchURL(testApplicationContext, testEnvSwitchInfo)
}
Above written test case is working fine. I need to find out how to write test case for switch condition for the above class. Kindly help me to write the same
I haven't answered your question, but perhaps refactoring your code slightly makes it more obvious to test:
private val SELECTED_ENV = "";
fun getEnvSwitchURL(applicationContext: Context, envSwitchInfo: String): String {
val resources = applicationContext.resources
val assetManager = resources.assets
val properties = Properties()
val selectedUrl: String
try {
val inputStream = assetManager.open("configuration.properties")
properties.load(inputStream)
val urlPref = applicationContext.getSharedPreferences(SELECTED_ENV, Context.MODE_PRIVATE)
val editor = urlPref.edit()
selectedUrl = get(envSwitchInfo, properties)
editor.putString("selectedUrl", selectedUrl)
editor.apply()
inputStream.close()
}
return selectedUrl
}
fun get(envSwitchInfo: String, properties: Properties): String {
when (envSwitchInfo) {
"Production" -> {
return properties.getProperty("prodUrl")
}
"Development" -> {
return properties.getProperty("devUrl")
}
"Testing" -> {
return properties.getProperty("testUrl")
}
else -> throw IllegalStateException("Unhandled environment $envSwitchInfo")
}
}
You could do a lot more here, look into the Single Responsibilty Principle. This is a start, for unit testing you don't want to test that SharePreferences works correctly because then you are testing the platform and not your code. You may want to test only that when you pass an environment like "Production", then the selectedUrl you get is returned.
Testing inputs and outputs as described above would be something like this:
String url = envSwitchUtils.getEnvSwitchURL(testApplicationContext, "Production")
assertEquals(url, "http://myProdUrl")
and another test
String url = envSwitchUtils.getEnvSwitchURL(testApplicationContext, "Development")
assertEquals(url, "http://myDevUrl")