Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the important issues in Android unit testing

2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "what are the important issues in Android unit testing". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn what are the important problems in Android unit testing.

1. How to solve the Android dependency?

Xiaobai: "TextUtils is used in Presenter, run junit Times' java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked' error... do you want to use robolectric?"

Don't worry, it's not time for robolectric yet!

Because junit runs on jvm, and jdk does not have android source code, classes such as TextUtils in android sdk cannot be referenced when running junit. Since there is no jdk, let's add it ourselves!

In the test/java directory, create the android.text.TextUtils class

Package android.text

Public class TextUtils {

Public static boolean isEmpty (CharSequence str) {

If (str = = null | | str.equals ("")) {

Return true

}

Return false

}

}

The key is to have a TextUtils same package name, same class name, and same method name. Note that it is not created under main/java, otherwise it will prompt Duplicate class found in the file.... The unit test runs properly:

The principle is simple: the jvm runtime looks for the android.text.TextUtils class and then looks for the isEmpty method to execute. Students who have studied java reflection know that as long as you know the package name, you can get the Class, and if you know a method name of this class, you can get the Method and execute it. Jvm is a similar mechanism, as long as we give a class with the same package name as android sdk and write a method with the same method name & parameter & return value, jvm can be compiled and executed.

(hint: android's View and the like can do the same.)

two。 Isolated Native method

Xiaobai: "I use the native method, junit fails to run, and robolectric does not support loading so files. What should I do?"

Model class:

Package com.test.unit; public class Model {public native boolean nativeMethod ();}

Unit test:

Public class ModelTest {Model model; @ Before public void setUp () throws Exception {model = new Model ();} @ Test public void testNativeMethod () throws Exception {Assert.assertTrue (model.nativeMethod ());}}

Run ModelTest... Error java.lang.UnsatisfiedLinkError: com.test.unit.Model.nativeMethod ()

The last article, "Android Unit testing-how to get started?" talked about "dependency isolation", which is used here!

Improve unit testing:

Public class ModelTest {Model model; @ Before public void setUp () throws Exception {model = mock (Model.class);} @ Test public void testNativeMethod () throws Exception {when (model.nativeMethod ()) .thenReturn (true); Assert.assertTrue (model.nativeMethod ());}}

Run again, pass:

Here's a little bit about java's process of finding the native method:

1) .Model.java full name is com.test.unit.Model.java

2)。 After calling the native method nativeMethod (), jvm goes to the C++ layer com_test_unit_Model.cpp, then to the com_test_unit_Model_nativeMethod () method, and calls it.

During the APP run, we will compile the cpp into a so file, and then load the APP into the dalvik virtual machine. But in the unit test, the corresponding so file was not loaded, and the cpp was not compiled! Daniel may try to load the so file when unit testing, but it is completely unnecessary and does not conform to the principles of unit testing.

So, we can just use the Mockito framework mock native method. In fact, not only native methods require mock, but many dependent methods and classes require mock. We'll talk about more common scenarios below.

(refer to "Android JNI principle Analysis")

3. Resolve internal new objects

Xiaobai: "I rely more on new Model,Model in Presenter, can do sql operation, and so on. Presenter relies on Model to return results, which makes Presenter unable to unit test! ask for advice!"

Example of rookie C: Model:

Public class Model {public boolean getBoolean () {boolean bo =. / / A bunch of dependencies, the code is very complex return bo;}}

Presenter:

Public class Presenter {Model model; public Presenter () {model = new Model ();} public boolean getBoolean () {return model.getBoolean ();}}

Faulty unit test:

Public class PresenterTest {Presenter presenter; @ Before public void setUp () throws Exception {presenter = new Presenter ();} @ Test public void testGetBoolean () throws Exception {Assert.assertTrue (presenter.getBoolean ());}}

It's the same thing: dependence and isolation. We isolate Model dependencies, that is, mock Model objects, instead of new Model ().

Look for the problem with PresenterTest above: PresenterTest is completely unaware of the existence of Model, which means you can't mock Model. So, we'll find a way to pass mock Model to Presenter-- and pass parameters in the Presenter constructor!

Improve Presenter:

Public class Presenter {Model model; public Presenter (Model model) {this.model = model;} public boolean getBoolean () {return model.getBoolean ();}}

Correct unit testing:

Public class PresenterTest {Model model; Presenter presenter; @ Before public void setUp () throws Exception {model = mock (Model.class); / / mock Model object presenter = new Presenter (model);} @ Test public void testGetBoolean () throws Exception {when (model.getBoolean ()) .thenReturn (true); Assert.assertTrue (presenter.getBoolean ());}}

That's how it worked out. If you find it convenient to use the default Presenter constructor directly in Activity and new Model () in the constructor, keep the default constructor. Of course, there are no multiple constructors with dagger2, all of which are passed parameters.

4. Static method

Xiaobai: "Big God, I use static methods in Presenter." The author: "all right, I know what you are going to say."

Presenter:

Public class Presenter {public String getSignParams (int uid, String name, String token) {return SignatureUtils.sign (uid, name, token);}}

The solution is more or less the same as the solution to internal new objects above, and the core idea is still dependency isolation.

1)。 Put sign (...) Change to non-static method

2)。 Use SignatureUtils as a member variable

3)。 The constructor is passed into SignatureUtils

4)。 When unit testing, pass the mock SignatureUtils to Presenter.

Improved Presenter:

Public class Presenter {SignatureUtils mSignUtils; public Presenter (SignatureUtils signatureUtils) {this.mSignUtils= signatureUtils;} public String getSignParams (int uid, String name, String token) {return mSignUtils.sign (uid, name, token);}}

5.RxJava changes from asynchronism to synchronization

Xiaobai: "the great god."

The author: "pinching and pointing for the teacher, I expect you to encounter this disaster."

Xiaobai: (from beginner to monk in legend?)

Public class RxPresenter {public void testRxJava (String msg) {Observable.just (msg) .subscribeOn (Schedulers.io ()) .delay (1 TimeUnit.SECONDS) / / delay 1 second / / .subscrieOn (AndroidSchedulers.mainThread ()) .subscribe (new Action1 () {@ Override public void call (String msg) {System.out.println (msg)) });}}

Unit testing

Public class RxPresenterTest {RxPresenter rxPresenter; @ Before public void setUp () throws Exception {rxPresenter = new RxPresenter (); @ Test public void testTestRxJava () throws Exception {rxPresenter.testRxJava ("test");}}

Run RxPresenterTest:

You will find that there is no output "test". Why?

Because in testRxJava, Obserable.subscribeOn (Schedulers.io ()) switches the thread to Io thread and delay for 1 second, while the testTestRxJava () unit test has already finished running on the current thread. The author has tried that even if delay (1, TimeUnit.SECONDS) is removed, it will not output 'test'.

We can see that the author has commented out .roomeon (AndroidSchedulers.mainThread ()). Let's add that code and run testTestRxJava (), and we will report java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.:.

This is because jdk does not have the class android.os.Looper and related dependencies.

To solve the above two problems, we just need to switch Schedulers.io () & AndroidSchedulers.mainThread () to Schedulers.immediate (). The RxJava development team has come up with two classes for hook operations, RxJavaHooks and RxAndroidPlugins.

Create a new RxTools:

Public class RxTools {public static void asyncToSync () {Func1 schedulerFunc = new Func1 () {@ Override public Scheduler call (Scheduler scheduler) {return Schedulers.immediate ();}}; RxAndroidSchedulersHook rxAndroidSchedulersHook = new RxAndroidSchedulersHook () {@ Override public Scheduler getMainThreadScheduler () {return Schedulers.immediate () }; RxJavaHooks.reset (); RxJavaHooks.setOnIOScheduler (schedulerFunc); RxJavaHooks.setOnComputationScheduler (schedulerFunc); RxAndroidPlugins.getInstance (). Reset (); RxAndroidPlugins.getInstance (). RegisterSchedulersHook (rxAndroidSchedulersHook);}}

Add a sentence RxTools.asyncToSync () to RxPresenterTest.setUp ():

Public class RxPresenterTest {RxPresenter rxPresenter; @ Before public void setUp () throws Exception {rxPresenter = new RxPresenter (); RxTools.asyncToSync ();}.}

Run testTestRxJava () again:

Finally output "test", thank God! (the author should be rewarded ^ _ ^)

Have you noticed that RxTools.asyncToSync () adds an extra word RxJavaHooks.setOnComputationScheduler (schedulerFunc), meaning to switch computation threads to immediate threads. The author found that only adding RxJavaHooks.setOnIOScheduler (schedulerFunc), for the Obserable with delay still failed, so conveniently switch the computation thread, so it is OK.

There are also RxJavaHooks.reset () and RxAndroidPlugins.getInstance (). Reset (), the author found that when running a large number of unit tests, some failed, but failed unit tests alone passed. After being puzzled, those two sentences were added. Yes!

At this point, I believe you have a deeper understanding of "what are the important issues in Android unit testing?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report