ถึงแม้จะเป็น Context เหมือนกัน แต่ในบางครั้งก็ใช้แทนกันไม่ได้นะ
ในการเขียนเทสแบบ Instrumented Test ก็อาจจะมีการเรียกใช้งาน Context เป็นบางครั้ง โดยนักพัฒนาสามารถดึง Context ในระหว่าง Instrumented Test ได้จากคลาสที่ชื่อว่า InstrumentationRegistry แบบนี้
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
ซึ่งเป็นคำสั่งที่คุ้นเคยกันดี เพราะคำสั่งดังกล่าวจะอยู่ในตัวอย่างการเขียนเทสของ Instrumented Test ที่มาพร้อมกับตอนสร้างโปรเจคใหม่บน Android Studio
แต่รู้หรือไม่ว่า จริง ๆ แล้วนักพัฒนาสามารถเรียกใช้งาน Context จาก InstrumentationRegistry ได้ทั้งหมด 2 รูปแบบด้วยกัน
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
val context: Context = InstrumentationRegistry.getInstrumentation().context
อ้าว ทำไมมีให้ใช้ทั้ง 2 แบบล่ะ? แล้วควรใช้แบบไหนกันแน่?
ถ้าจะให้ตอบแบบสั้น ๆ ก็คือ targetContext
เป็น Context ของแอปหลักที่เราพัฒนาขึ้นมา ส่วน context
เป็น Context ของแอปที่เกิดมาจาก Instrumented Test
แต่เพื่อให้เข้าใจมากขึ้น...
สิ่งที่เกิดขึ้นเมื่อนักพัฒนาสั่งให้ Instrumented Test ทำงาน
ในการทำงานของ Instrumented Test นั้น โค้ดที่นักพัฒนาเขียนไว้สำหรับเทสจะไม่ได้ถูกรวมอยู่ในแอปหลักโดยตรง แต่ Android Studio จะสร้างเป็นแอป 2 ตัวเพื่อติดตั้งลงในอุปกรณ์แอนดรอยด์
- แอปตัวที่ 1 - แอปที่เราพัฒนาขึ้นมาตามปกติ
- แอปตัวที่ 2 - แอปที่มีโค้ดสำหรับ Instrumented Test
นั่นจึงเป็นที่มาว่าทำไมคลาส Instrumentation
มี targetContext
และ context
ให้เรียกใช้งานแยกกัน เพราะเป็น Context ของแอปคนละตัวนั่นเอง
และเป็นที่มาของtestApplicationId
ในbuild.gradle
ด้วย เพื่อให้นักพัฒนากำหนด Package Name หรือ Application ID สำหรับแอปที่เป็น Instrumented Test ได้ตามใจชอบ
ตั้งชื่อใหม่ จะได้ไม่สับสน
เนื่องจากทั้งคู่ก็เป็น Context เหมือนกัน ทำให้โค้ดตัวอย่างของ Instrumented Test มีการประกาศชื่อตัวแปรไว้อย่างชัดเจนว่าเป็น Context ของอะไร
เพื่อไม่ให้สับสนระหว่าง Context ทั้ง 2 ตัวนี้ จึงแนะนำให้กำหนดเป็นชื่อตัวแปรไว้แบบนี้แทน
val appContext: Context = InstrumentationRegistry.getInstrumentation().targetContext
val testContext: Context = InstrumentationRegistry.getInstrumentation().context
และเนื้อหาต่อจากนี้เจ้าของบล็อกจะใช้คำว่าappContext
และtestContext
แทน
เมื่อ Context ต่างกัน Resource ที่มีให้เรียกใช้งานก็จะต่างกัน
โดย appContext
จะเป็น Resource ใน Source Set ที่ชื่อว่า main
src/main/res
src/main/resources
src/main/assets
ส่วน testContext
จะเป็น Resource ใน Source Set ที่ชื่อว่า androidTest
src/androidTest/res
src/androidTest/resources
src/androidTest/assets
ดังนั้นการเข้าถึงข้อมูลจำพวก Resource เหล่านี้นอกจากจะต้องกำหนด Resource ID / Path ให้ถูกต้องแล้ว ก็จะต้องเรียกใช้งาน Context ให้ถูกต้องด้วยเช่นกัน ไม่เช่นนั้นจะเกิดปัญหา NotFoundException
ขึ้นได้