一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android Testing :: testing private methods | OCTO talks !

 tracyf 2015-11-23


This article is about testing private methods in android. This is a fairly common problem in android (even in Java at large) and can be solved easily. The technique proposed here provides the additionnal benefit of using a traditional way of solving the problem in the Java world. (suspense :) )


Using the android platform, you are used to divide your application into two projects :



  • one for the main source code of your application,

  • one for the tests



This is a mandatory structure on android, stongly emphasized by Google. Even, if you use the android-maven-plugin, you follow this pattern, and it is also the case if you use robolectric.


Moreover, it is a common practice to name the packages of your application using the following convention (inside the AndroidManifest.xml files of both projects) :



  • foo.bar

  • foo.bar.tests


Where foo.bar follows more or less your web domain name in the reverse order.


If you use the same package names to name the packages of your class, and this is a fairly common and intuitive practice, then you will face a big trouble : you will only be able to test your public methods : a test class inside a package named foo.bar.tests won’t be able to access the private and protected methods of a class in the package foo.bar. For instance :


In your app under test :



1
2
3
4
5
package foo.bar;
 
public class Foo {
    protected int m()  { return 2 };
}


In your test app :



1
2
3
4
5
6
7
8
9
10
package foo.bar.test;
 
import android.test.AndroidTestCase;
 
public class FooTest extends AndroidTestCase {
    public void testFoo() {
        //m() is not accessible from Foo
        assertEquals( 2, new Foo().m() );   //should not compile
    }
}


This code would generate a compile error. The method m() is only accessible to the classes that belong to the package foo.bar and the notion of subpackages doesn’t exist in the Java programming language.


Consequently you have several options.


1. Consider testing only public methods. Actually, this makes a lot of sense. Object-Oriented programming strongly emphasize the notion of contract and testing internals of a class can appear as violation of the notion of encapsulation.


Nevertheless, there are some cases where you really want to test some internal methods as they are complex, or just as they contain more of the logic of the class than public methods, or because you divided the different problems faced by public methods into some more specialized private methods (and this is a very good practice in IT, the famous divide and conquer principle).


2. Subclassing your class under test is an alternative : you can use protected methods in your class under test. And, in your tests, whenever you need to test a protected method, although you can’t invoke it directly, you can create a smaller inner class of the test class that extends the class under test and overrides every protected methods under test. This overridden method will just just invoke the super method, just to re-give it a package level visibility. The inner class protected methods will then be visible to the test class as they now belong to the same package.


Here is an example of this technique :


In your test app :



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package foo.bar.test;
 
import android.test.AndroidTestCase;
 
public class FooTest extends AndroidTestCase {
    public void testFoo() {
        //m() is not accessible from Foo 
        //but it is from FooUnderTest
        assertEquals( 2, new FooUnderTest().m() );
    }
 
    private class FooUnderTest extends Foo {
        @Override
        protected int m() { super.m() };
     }
}



Although it is a common and accepted practice in Java to give a normally private method a protected visibility just to accomodate the case, purists are still under shock (and I belong to that camp), but that’s nevertheless a standard in Java. But this example demonstrates the drawback of this technique as well : it requires a huge, almost useless, amount of code, just a workaround and syntactic solution to a Java problem, but contains no interesting logic and is, indeed, a useless and thus painful programming effort. Nevertheless it could please purists as there is no need to alter the system under test only for testing purposes.


3. Using introspection is also possible. Reflexion allows to bypass the built-in visibility mechanism of Java. It allows to invoke any private / protected method on an object, or to use a private / protected field.


Here is an example :


In your test app :



1
2
3
4
5
6
7
8
9
10
11
12
package foo.bar.test;
 
import android.test.AndroidTestCase;
 
public class FooTest extends AndroidTestCase {
    public void testFoo() {
        Method method = targetClass.getDeclaredMethod("m", new Class[0]);
        method.setAccessible(true);
        int actual = method.invoke( new Foo(), new Object[0]);
        assertEquals( 2, actual );
    }
}


Although this leads to some much more cryptic syntax and make you loose the ability to refactor your code easily (as you will have to hard code method under test names in your tests), this technique is only one that can be used to test a really private method. It will please purists as there is no need to alter the system under test only for testing purposes.


4. Avoid naming your Java packages in the same way as you name you Application package :  in other words, there is absolutely no obligation to use the same name in your Java package and inside your AndroidManifest.xml.It was a bad idea from Google to call a “package” the app identifier inside an AndroidManifest file. This “package” is indeed an ID for your application inside google market for instance but it imposes no kind of constraints on Java packages inside your app and has indeed nothing to do with them.



Here is an example :


In your test app AndroidManifest.xml:



1
2
3
 ...
 package="foo.bar.test"
 ...


In your test app Java classes :



1
2
3
4
5
6
7
8
9
10
package foo.bar; //<---That's the point !!
 
import android.test.AndroidTestCase;
 
public class FooTest extends AndroidTestCase{
    public void testFoo() {
        //m() is now accessible directly from Foo
        assertEquals( 2, new Foo().m() );
    }
}


How does this work ? Simply because test classes and classes under test will be loaded inside the same Dalvik VM, all classes loaded from both apps and test-apps will be merged at runtime. Thus there is no difference in placing a class in an app or another on this specific matter (but please note that a class under test can’t depend on any class that is found in the test app dex/apk, this would result in an exception ‘ClassNotFoundException : class loaded from the wrong dex’).


Conclusion

This latter approach is much simpler than anything else and relies on the common Java practice of giving the protected visibility level to private methods for the sole purpose of testing them.


By using the same package for your test classes and your classes under test, you can test very simply internal methods and the package structure of your test app is much clearer.


Moreover, there is an additional benefit : you can use the eclipse “create junit test” wizard on your class under test (right click on the class under test and find it in the “New >> JUnit Test Case” option). Just change the source folder field of the wizard and choose your test app source folder instead of the app folder.




This article is the first of a serie of articles that will be dedicated to testability of android applications, one of the axis of research inside the Mobile Development Team @ Octo Technology.




  

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    亚洲精品国产精品日韩| 午夜福利大片亚洲一区| 亚洲国产成人av毛片国产| 大香蕉精品视频一区二区| 欧美一级不卡视频在线观看| 国产偷拍盗摄一区二区| 在线一区二区免费的视频| 久久精品久久精品中文字幕| 久久福利视频这里有精品| 欧美色欧美亚洲日在线| 中国一区二区三区不卡| 激情综合网俺也狠狠地| 国产亚洲欧美自拍中文自拍| 91偷拍裸体一区二区三区| 中日韩美女黄色一级片 | 一二区中文字幕在线观看| 久久国产成人精品国产成人亚洲| 国产成人精品资源在线观看| 久久精品中文扫妇内射| 日韩蜜桃一区二区三区| 微拍一区二区三区福利| 免费在线观看激情小视频| 久久午夜福利精品日韩| 高清国产日韩欧美熟女| 熟妇人妻av中文字幕老熟妇| 精品人妻一区二区三区在线看 | 欧美成人免费夜夜黄啪啪| 国产成人精品国内自产拍| 加勒比日本欧美在线观看| 一区二区三区四区亚洲另类| 亚洲一区在线观看蜜桃| 日本理论片午夜在线观看| 亚洲欧洲日韩综合二区| 国产毛片不卡视频在线| 欧美韩日在线观看一区| 亚洲天堂国产精品久久精品| 亚洲日本中文字幕视频在线观看| 五月婷婷综合激情啪啪| 国产在线不卡中文字幕| 好吊妞视频免费在线观看| 欧美精品女同一区二区|