버튼 수집상

[안드로이드] 중복체크 되는 리스트 Preference 저장하고 테스트하기 본문

TIL - 안드로이드

[안드로이드] 중복체크 되는 리스트 Preference 저장하고 테스트하기

cocokaribou 2023. 7. 20. 14:08

배경

최근본상품 api를 만드는 대신, 상품을 열람할 때마다 앱 내부에서 열람 히스토리를 갱신시키기로 했다.

내부DB를 써도 됐지만 상품번호 문자열만 저장하면 돼서 Preference 프리퍼런스를 사용했다.

 

1. 새로운 요소 - 리스트 0번째에 저장

2. 중복되는 요소 - 기존 요소 삭제, 리스트 0번째에 저장

 

기본 코드

Preference

// 리스트 자료형을 직렬화해서 문자열로 저장
var recentProducts: String
    get() = preferences.getString(KEY_RECENT_PRODUCTS, null) ?: ""
    set(value) = preferences.edit {
        putString(KEY_RECENT_PRODUCTS, value)
}

최근본상품 중복체크해서 저장

// 최근본상품 중복체크해서 저장
// 개수제한 없음
fun addRecentProduct(prdNo: String) {
    val list = getRecentProducts()
    
    list.checkDupeThenAdd(prdNo)
    
    val convertedString = list.joinToString(separator = ",")
    recentProducts = convertedString
}

 

리스트 중복체크

// 중복체크
private fun ArrayList<String>.checkDupeThenAdd(input: String) {
    if (isEmpty()) {
    	add(input)
        return
    }
    
    var dupeIndex = indexOf(find { it == input })
    if (dupeIndex != -1) {
         removeAt(dupeIndex)   
    }
    add(0, input)
}

최근본상품 preference 제어

// 최근본상품 가져오기
// 문자열 프리퍼런스 -> ArrayList
fun getRecentProducts(): ArrayList<String> {
    return arrayListOf(*recentProducts.split(",").toTypedArray())
}

// 최근본상품 비우기
// 문자열 프리퍼런스에 빈 값 할당
fun clearRecentProducts() {
    preferences.edit {
        putString(KEY_RECENT_PRODUCTS, "")
    }
}

 

개선

중복되는 요소가 없는 집합(Set) 자료형을 쓰면 checkDupeThenAdd 함수를 따로 만들 필요가 없었다.

// 문자열 프리퍼런스 -> ArrayList
val recentProductList
    get() = arrayListOf(*recentProducts.split(",").toTypedArray())

// 최근본식당 중복체크해서 저장
// 개수제한 없음
fun addRecentProduct(prdNo: String) {
    val list = recentProductList
    list.add(0, prdNo)

    // toSet() 으로 중복되는 요소 제거
    // 프리퍼런스에 바로 저장
    recentProducts = list.toSet().toList().joinToString(separator = ",")
}

 

테스트하기

상품을 직접 열람하지 않고 JUnit4를 이용해 테스트 코드를 작성했다.

 

assertEquals 보다 신택스가 훨씬 직관적인 Truth 라이브러리를 쓰겠다.

build.gradle(:app)

testImplementation "com.google.truth:truth:1.0.1"
androidTestImplementation "com.google.truth:truth:1.0.1"

Preference는 안드로이드 라이브러리이므로

유닛테스트(app/src/test)가 아닌 안드로이드 테스트(app/src/androidTest)를 해야한다.

DataManagerTest.kt

import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class DataManagerTest {
    lateinit var dataManager : DataManager
    
    /** 매 테스트마다 초기화 코드 **/
    @Before
    fun setup() {
        dataManager = DataManager //싱글턴 오브젝트
        dataManager.clearRecentProducts()
    }

    /** 리스트[0]에 입력값과 중복되는 요소 저장 방지 **/
    @Test
    fun prevent_adding_duplicated_item_to_the_first_index() {
        val testCases = arrayListOf("[0]", "[1]", "[2]", "[3]", "[4]")
        for (string in testCases) {
            dataManager.addRecentProduct(string)
        }

        dataManager.addRecentProduct("[0]")
        assertThat(dataManager.recentProductList).containsNoDuplicates()
    }

    /** 입력값과 중복되는 요소가 [0]이 아닌 자리에 있다면 그 자리의 요소를 지우고 [0]에 입력값 저장
     * 예)
     * 2 삽입 -> [1, 2]
     * [2, 1] ✅
     * [2, 1, 2] ❌
     * [1, 2] ❌
     * **/
    @Test
    fun add_latest_item_to_the_first_index() {
        val testCases = arrayListOf("[0]", "[1]", "[2]", "[3]", "[4]")
        for (string in testCases) {
            dataManager.addRecentProduct(string)
        }

        dataManager.addRecentProduct("[3]")
        val result = dataManager.recentProductList[0] == "[3]"
        assertThat(result).isTrue()
    }
}

JUnit 테스트 함수는 시스템에서 호출하므로 함수명을 snake_case로 길게 달았다.

이러면 앱을 직접 사용하지 않아도 최근본상품 기능이 정상동작하는지 확인할 수 있다.

 

728x90