In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Xiaobian to share with you how to test RxJava code, I hope you have something to gain after reading this article, let's discuss it together!
Responsive programming requires a shift in the way we reason about a given problem because we focus on flowing data as a stream of events rather than individual data items. Events are usually generated and consumed by different threads, so you must have a clear understanding of concurrency issues when writing tests. Fortunately, RxJava provides built-in support for testing Observables and Subscriptions, built directly into RxJava's core dependencies.
the first step
Let's review the example of that vocabulary given in "Getting Started with RxJava Instance Parsing" and see how to test it. Let's start with the basic test tool setup. In our test architecture, JUnit was used as a test tool.
In fact, without a scheduler, subscriptions will default to running on the calling thread. So we will use native methods in *** tests. This means that we can implement an object of the Subscription interface that asserts its state as soon as a Subscription occurs.
Note that an explicit List container is used here, aggregating results with actual subscribers. The simplicity of the given test might lead you to think that this explicit accumulator approach is good enough. But remember that production-level Observables may encapsulate errors or generate unexpected events. The simple combination of Subscriber and Accumulator in the example is not sufficient to cover this situation. But don't worry about that; RxJava provides TestSubscriber types to handle this. Next we refactor the test above using the TestSubscriber type.
TestSubscriber not only replaces the user accumulator, but also gives some additional behaviors. For example, it can give the size of the message received and the data associated with each event, and it can also assert that the Subscription is complete and no errors occur during the Observable consumption. Although Observable in the current test did not generate any errors, going back to the article "RxJava Getting Started with Instance Parsing," we learned that Observable treats exceptions as data events. We can simulate errors by concatenating exceptional events as follows:
All mechanisms work well in the limited use cases we present. However, the actual product code may be completely different from the example. So in the following we will consider some more complex product examples.
Custom Scheduler
In production code, Observables in many use cases execute on a specific thread, which is called a "Scheduler" in a reactive programming environment. Many Observable operations use optional scheduler parameters as additional parameters. RxJava defines a series of named schedulers available at any time, including IO scheduler (io), computation scheduler (shared thread), and new thread scheduler (newThread). Developers can also implement custom dispatchers. Let's modify Observable's code by specifying a compute scheduler.
When running, you will immediately find that the code is problematic. Subscriber executes its assertions on the test thread, but Observable generates values on the background thread (the compute thread). This means that executing a Subscriber assertion may generate all relevant events before Observable, thus causing the test to fail.
To make the test run smoothly, there are some strategies to choose from:
Convert Observable to blocking.
Force the test to wait until the given conditions are met.
Converts a compute scheduler to an immediate (Scheduler.immediate()) scheduler.
We'll expand on each policy, but we'll start with "Turn Observable to Blocking," because implementing that policy requires minimal technical effort, regardless of the scheduler used. We assume that the data is generated in a background thread, which will cause Subscribers to be notified from the same background thread.
What we want to do is force all events to be generated and complete Observable in the test before the next declaration is executed. This is done by calling the toBlocking() method on the Observable itself.
Although this method works for the simple code we give, it may not work for the actual product code. If it takes a long time for producers to generate all the data, what will happen? This will make testing very slow and increase compilation time, and there may be other performance issues. A handy library I recommend here is Awaitility(https://github.com/awaitility/awaitility). Simply put, Awaitility is a DSL that expresses expectations associated with asynchronous systems in a precise, easy-to-read manner. Maven can be used to add Awaitility dependencies to a project.
org.awaitility awaitility 2.0.0 test
Or use Gradle:
testCompile 'org.awaitility:awaitility:2.0.0'
The access point for Awaiteness DSL is the org.awaitility.await.await() method (see lines 13 and 14 in the example below). You can use Awaiting to define the conditions that must be met for the test to continue, or you can add timeouts or other timing constraints to the conditions, such as minimum, ***, or duration. For the example above, the following code shows how to use Awaiteness in the result:
This version of the test does not change the nature of Observable in any way, which allows you to test without having to make any changes to the product code. This version of the test uses a wait time of up to 2 seconds for Observable to perform its job by checking Subscriber status. If all goes well, the Subscriber's state is released to all nine events in 2 seconds.
Awaitility works well with Hamcrest's matchers, Java 8 lambda expressions, and method references to give precise and readable test conditions. Awaitility also provides prefabricated extensions for widely used JVM languages, including Groovy and Scala.
We're going to give *** a policy that uses RxJava extensions that are published as part of the RxJava API. RxJava defines a series of extension points that allow fine-tuning of almost any default RxJava behavior. This extension mechanism allows us to provide modified values for specific RxJava features. Using this mechanism, we can inject selected schedulers into tests without caring about the scheduler specified in the generated code. This is exactly what we are looking for, encapsulated in the RxJavaHooks class. Assuming that the product code depends on a compute scheduler, we will override its default value and return a scheduler that causes event handling to occur as the code called, which is the immediate scheduler (Scheduler.immediate()). The code for the test is given below:
In testing, the production code was unaware that the computation scheduler was instantaneous. Note that the hook function must be reset, otherwise the immediate scheduler settings may leak, causing tests to be broken everywhere. Using the try/finall block obscures the purpose of the test somewhat, but fortunately we can refactor this behavior using JUnit rules to make the test more refined and the results more readable. One possible implementation code using the above rule is given below:
In addition, we have rewritten the generation methods for the other two schedulers. This rule is more general to other test targets thereafter. In the new test case class, the rule is straightforward to use, simply defining a domain and labeling the new type @Rule. The sample code is as follows:
Eventually we get the same behavior as the previous test, but without the clutter. Here is a brief review of what we have done so far:
Subscribers will process data in the same thread as long as no particular scheduler is used. This means that after a Subscriber subscribes to an Observable, we can make assertions on that Subscriber.
TestSubscriber accumulates events and gives additional assertions of its own state.
Any Observable can be converted to blocking, which allows us to wait synchronously for events to be generated regardless of what scheduler the Observable uses.
RxJava provides extension mechanisms that allow developers to override their default methods and inject them into production code in an appropriate way.
Concurrent code can be tested using Awaiteness DSL.
Each of these techniques works in a different scenario, but all are related by a "common thread": the test code waits for Observable to complete before asserting Subscriber status. Given that Observable's behavior generates data, is there a way to check that behavior? In other words, is it possible to do Observable field debugging programmatically? We shall present such techniques later.
control time
So far we have tested Observables and Subscriptions in black boxes. Next we consider another technique for manipulating time, which allows us to open the hood to view Subscriber status while Observable is still active. In other words, we'll use TestScheduler white box testing techniques with RxJava, which is RxJava saving the day once again. This particular scheduler can precisely set the internal use of time, such as advancing it by half a second or jumping it by five seconds. We'll show you how to create an instance of this new scheduler first, and then we'll talk about testing the code.
The "product" code has changed slightly because we used a method bound to scheduler interval() to generate counts (line 6) instead of generating a range of counts. But this has the side effect that counts are generated from zero instead of 1. Once Observable and the test scheduler are configured, we immediately make the assertion that Subscriber has no value (line 15) and has not been completed or generated any errors (line 16). This is an integrity test because the scheduler has not been moved, so no values are generated by Observables or received by Subscribers.
Moving the time forward by one full second (line 19) causes Observable to generate *** values, which are checked for subsequent assertion sets (lines 22 through 24).
Now adjust the time from the current time to 9 seconds. Note that this means adjusting the time exactly to 9 seconds after the scheduler starts (not 1 second forward and 9 seconds forward, i.e. 10 seconds after the scheduler check starts). In other words, the advanceTimeBy() method adjusts the scheduler's time relative to the current location, while advanceTimeTo() adjusts the time in absolute terms. After that we make the next round of assertions (lines 28 to 20) to ensure that all data is generated by Observables and consumed by Subscribers. Another thing to note is that when using TestScheduler, the real time is adjusted immediately, which means the test doesn't actually wait 9 seconds to complete.
As you can see, the scheduler is very convenient to use, simply by providing the scheduler to the Observable under test. But for Observables that use a scheduler of the specified type, the scheduler does not work well. But wait a minute, earlier we saw how to use RxJavaHooks to switch a scheduler that doesn't affect production code, and this time it provides a TestScheduler instead of an immediate scheduler (lines 13 to 15). We can even apply the same techniques for customizing JUnit rules so that previous code can be rewritten in a more reusable way. First of all, the new rule is:
Next comes the actual test code (in a new test case class) to use our test rules:
So you have succeeded in achieving it. Using the method of injecting TestScheduler via RxJavaHooks, you can write test code without changing the original Observable composition, and it gives you a way to vary the time during the execution of the observables themselves and make assertions at specific points. All of the techniques presented in this article should be sufficient to select code to test RxJava.
After reading this article, I believe you have a certain understanding of "how to test RxJava code". If you want to know more about it, please pay attention to the industry information channel. Thank you for reading!
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.