02 พฤษภาคม 2558

[Android Code] ลองทำ Unit Test บน Android Studio กันเถอะ



        การเขียนเทสนั้นสำคัญแค่ไหนก็รู้กันอยู่แล้ว ถึงแม้ว่าจะไม่ค่อยเขียนกันซักเท่าไร (เจ้าของบล็อกก็เช่นกัน) สำหรับบทความนี้จะเป็นการทำ Local Unit Test บน Android Studio เพื่อเอาไว้เขียนเทสในส่วนของ Unit Test ให้กับโปรเจคของผู้ที่หลงเข้ามาอ่าน ซึ่งจะไม่ได้หมายถึง Instrumentation Test นะครับ (กำลังเขียนอยู่)

        ในตอนนี้การสร้างโปรเจคบน Android Studio เวอร์ชัน 1.4 ทุกๆครั้ง ตัวโปรแกรมก็จะมีการสร้างไฟล์สำหรับ Unit Test มาให้พร้อมแล้ว แต่ถ้าผู้ที่หลงเข้ามาอ่านยังใช้เวอร์ชันที่ต่ำกว่าหรือต้องการสร้าง Unit Test บน Module ตัวอื่นๆก็สามารถทำได้ดังนี้

อย่าลืมเพิ่ม Dependencies ของ JUnit

        เพราะ Test Unit บน Android Studio นั้นจะใช้ JUnit เป็นหลัก จึงจำเป็นจะต้องเพิ่มเข้าไปใน Dependencies ของ Module ที่จะเขียนเทสดังนี้

dependencies {
    ...

    testCompile 'junit:junit:4.12'
}

        แต่ถ้าใช้ Android Studio 1.4 จะเพิ่มให้ทันทีตั้งแต่ตอนสร้างโปรเจคเลย

สร้างไฟล์สำหรับ Unit Test

        โดยปกติแล้วโฟลเดอร์สำหรับ Unit Test จะมีชื่อว่า test และจะอยู่ในโฟลเดอร์ src ของ Module ที่ต้องการทำ Unit Test



        แต่ถ้ายังไม่มีก็สร้างขึ้นมาซะเลย โดยเจ้าของบล็อกแนะนำว่าให้ปรับมุมมองของ Project Explorer ให้เป็นแบบ Project แทน เพราะถ้าดูแบบ Android จะสร้างลำบาก





        จากนั้นก็สร้างโฟลเดอร์  java ไว้ในนั้น จะเห็นว่า Android Studio มีการโฟกัสโฟลเดอร์ java เป็นแถบสีเขียวๆไว้ให้



        แล้วสร้าง Package ขึ้นมาโดยอิงตาม Module นั้นๆซะ


        เพิ่มเติม ชื่อ Package ควรตั้งให้ตรงกับไฟล์ที่ต้องการเทส ถึงแม้ว่ามันจะตั้งไม่เหมือนกันก็ได้ แต่มันจะมีปัญหาเวลาเรียกคำสั่งมาเทส ซึ่งเสียเวลาต้องมานั่งประกาศ Import ทุกครั้ง เพราะงั้นใช้ชื่อ Package ให้เหมือนๆกันแหละดีแล้ว

สร้าง Test Class

        ยกตัวอย่างว่านี่คือโค๊ดที่เจ้าของอยากจะทำ Unit Test ซึ่งเป็น Utility Class ที่สร้างขึ้นมาเอาไว้ใช้งานภายในโปรเจค

StringUtils.java
public class StringUtils {

    public static String wrapBlank(String message) {
        return (message != null && !message.equalsIgnoreCase("null")) ? message.trim() : "";
    }

    public static String concat (String message1, String message2) {
        if (message1 == null || message2 == null) 
            return null;
        return message1 + message2;
    }

}

        ซึ่งเจ้าของบล็อกต้องการเขียนเทสให้กับ 2 คำสั่งนี้ ดังนั้นก็สร้างคลาสสำหรับเทสขึ้นมาซะ เป็น Java Class ธรรมดานี่แหละ


        ในการตั้งชื่อไฟล์ดังกล่าวสามารถตั้งเป็นชื่อไฟล์อะไรก็ได้ ขอแค่ว่าอย่าไปซ้ำกับชื่อไฟล์ในโค๊ดหลักก็พอ ดังนั้นส่วนใหญ่จึงทำนิยมใส่คำว่า Test ต่อท้าย (แบบสิ้นคิด แต่ก็เข้าใจได้ง่ายที่สุด)

        อันนี้คือตัวอย่างโค๊ดสำหรับเทส 2 คำสั่งที่ยกตัวอย่างขึ้นมา

StringUtilsTest.java
import org.junit.Assert;
import org.junit.Test;

public class StringUtilsTest {

    @Test
    public void runWrapBlank() {
        String message = "Hello World";
        String result = StringUtils.wrapBlank(message);
        Assert.assertEquals("Hello World", result);

        message = null;
        result = StringUtils.wrapBlank(message);
        Assert.assertEquals("", result);

        message = "null";
        result = StringUtils.wrapBlank(message);
        Assert.assertEquals("", result);

        message = "That's null";
        result = StringUtils.wrapBlank(message);
        Assert.assertEquals("That's null", result);

        message = "Null";
        result = StringUtils.wrapBlank(message);
        Assert.assertEquals("", result);
    }

    @Test
    public void runConcat() {
        String message1 = "Hello";
        String message2 = "World";
        String result = StringUtils.concat(message1, message2);
        Assert.assertEquals("HelloWorld", result);

        message1 = null;
        message2 = "Awesome";
        result = StringUtils.concat(message1, message2);
        Assert.assertEquals("nullAwesome", result);

        message1 = null;
        message2 = null;
        result = StringUtils.concat(message1, message2);
        Assert.assertEquals(null, result);
    }

}

        สำหรับชื่อฟังก์ชันก็สามารถตั้งชื่ออะไรก็ได้ ขอแค่กำหนด Annotation ไว้ที่ข้างบนว่า @Test เพียงเท่านี้ก็จะเป็นคำสั่งสำหรับ Unit Test แล้ว ที่เหลือก็แค่เขียนโค๊ดเทสให้ครอบคลุมที่สุดซะ

พร้อมแล้ว รันได้เลย~

        ก่อนจะเริ่มรันให้ Build เป็น Unit Test ก่อน โดยกดเปิดหน้าต่าง Build Variants ขึ้นมา ที่ช่อง Test Artifact ให้เปลี่ยนเป็น Unit Tests แต่ถ้าเลือกเป็น Unit Tests อยู่แล้ว ก็ให้เลือกกลับไปเลือก Android Instrumentation Tests ก่อน แล้วกลับมาเลือกเป็น Unit Tests ใหม่


        แล้วโปรเจคจะทำการ  Build ให้นั่งรอซักครู่จนเสร็จ

        ให้สังเกตที่ช่อง Run ข้างบนตรงแถบเมนู จะเห็นว่ามี Run Configuration เพิ่มเข้ามาให้ ดังนั้นเวลาจะ Build สำหรับ Unit Test ก็ให้มากดตรงนี้แทนได้เลย ไม่ต้องไปนั่งกดที่ Build Variants แล้ว



        เท่านี้ก็เตรียมพร้อมครบหมดแล้ว อยากจะเทสที่ไฟล์ไหนก็ให้คลิกขวาที่ไฟล์นั้นๆแล้วเลือก Run '<ชื่อไฟล์>' ได้เลย


ผลลัพธ์ที่ได้จากการรัน Unit Test

        หลังจากที่รัน Unit Test เสร็จแล้วก็จะมีหน้าต่างแสดงผลลัพธ์ให้ดูบน Android Studio


        ที่หน้าต่างฝั่งซ้ายมือคือการเทสต่างๆที่ทำการรัน อันที่ผ่านก็จะเป็นวงกลมสีเขียวอยู่ข้างหน้า แต่ถ้าไม่ผ่านจะเป็นวงกลมสีส้ม และจะมีรายละเอียดแสดงที่ฝั่งซ้ายมือด้วย ก็ไปดูให้เรียบร้อยซะว่าเพราะอะไร สามารถกดที่ <Click to see difference> ได้ด้วยนะเออ เพื่อดูค่า Expected ที่กำหนดไว้และค่า Actual ที่ได้



        แต่ถ้าเทสสำเร็จ ผ่านไปได้ด้วยดีก็จะขึ้นแบบนี้



        ถ้าแสดงไม่เหมือนกับเจ้าของบล็อก (มีการบอกชื่อฟังก์ชันที่ทำการเทส) แต่มีแค่ All Test Passed แสดงบอก ก็เป็นเพราะว่าโปรแกรมไปติ๊กเลือก Hide Passed ไว้ (วงกลมสีแดงในภาพข้างล่าง) เพราะเวลาเขียนเทสเยอะๆ จะสนใจผลลัพธ์เฉพาะอันที่ไม่ผ่าน


เพิ่มเติม

        ถ้าเคยคลิกขวาที่ไฟล์แล้วกดรันแล้ว ครั้งต่อไปก็ไม่จำเป็นต้องไปคลิกขวาใหม่ เพราะสามารถเลือกจากใน Run Configuration ได้เลย



        ในกรณีที่เขียนเทสไว้หลายไฟล์และต้องการให้มันรันพร้อมๆกันทีเดียว ก็เข้าไปกำหนดเพิ่มเติมใน Run/Debug Configuration ได้เลย โดยเลือกที่ Edit Configurations...



         ซึ่งในนี้สามารถกำหนดได้ว่าจะให้รันเฉพาะบางไฟล์ หรือเลือกหลายๆไฟล์ก็ได้ หรือรันแค่เฉพาะบางโฟลเดอร์ หรือรันมันทั้งหมดทุกไฟล์เลยก็ยังได้ ซึ่งสามารถสร้างเป็น Configuration เก็บไว้ในโปรเจคได้เลย


สรุป

        บน Android Studio 1.4 ก็ได้เพิ่มไฟล์ในส่วน Unit Test เข้ามาเพื่อให้ง่ายขึ้น ผู้ที่หลงเข้ามาอ่านไม่จำเป็นต้องสร้างไฟล์เอง แต่ถ้าไม่มีก็สามารถสร้างเองได้เลย ซึ่งการทำ Unit Test บน Android Studio ก็ค่อนข้างสะดวก หลักๆก็จะอยู่ที่การเขียนโค๊ดสำหรับเทสเป็นหลักเลย

        สำหรับผู้ที่หลงเข้ามาอ่านที่สนใจศาสตร์แห่งการเทส ก็แนะนำให้ลองหาข้อมูลเพิ่มเติมดูนะครับ ซึ่งมันเป็นเรื่องที่กว้างพอสมควร และสามารถติดตามอ่านได้จากบล็อก www.somkiat.cc ของพี่ปุ๋ยครับ

        ส่วนโค๊ดตัวอย่างในบทความนี้สามารถดาวน์โหลดได้ที่

        • Unit Test Sample [Sleeping For Less]
        • Unit Test Sample [Google Drive]


เพิ่มเติมจากพี่ปุ๋ย Somkiat.cc

        บทความนี้จะเห็นว่าเป็นการเทสโค๊ดในส่วนที่ไม่ได้เกี่ยวข้องกับแอนดรอยด์โดยตรง เป็นแค่เพียงโค๊ดจาวาธรรมดา (Plain Java Code) ดังนั้นก็ควรแยกโค๊ดเหล่านี้ออกมาเป็นอีกเป็น Module แยกไปเลย เพื่อให้มันเทสได้ไว เพราะการรวมไว้ใน Module เดียวกันกับโค๊ดของแอนดรอยด์จะทำให้ทำงานได้ช้าลง



        ทำแยกออกมาเป็น Java Library แล้วค่อยให้ Module หลักไปเรียกใช้งานแบบนี้แทน ส่วนเขียนเทสก็ทำลงใน Java Library ตัวนั้นไปเลย

ขอให้สนุกกับการเขียนเทสจ้า




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium