I try to write unit tests like shown in RouteGuideServerTest.java. The fact is that my service reads some user context info (like userID, ip and etc.) from Context.Key<UserContext> which is set in some UserContextInterceptor.
The problem is that I don't want to same create interceptor in JUnit testing code and want to set Context manually right in the test method but cannot find the way to make it properly.
I have some Context.Key<UserContext> USER_CONTEXT in Constant.java and tried to set Context the next way:
Context.current().withValue(Constant.USER_CONTEXT, userContext).run(() -> { // some testing code })
but as the run happens in different thread from caller thread the context returned from Constant.USER_CONTEXT.get() is always null in service code.
Constant.java:
public static final Context.Key<UserContext> USER_CONTEXT = Context.key("userContext");
GrpcService.java
#Override
public StreamObserver<EntityRequest> process(StreamObserver<EntityResponse> responseObserver) {
return new StreamObserver<EntityRequest>() {
#Override
public void onNext(EntityRequest request) {
Constant.USER_CONTEXT.get(); // is always null in tests
}
// other methods
};
}
GrpcServiceTest.java
#Test
public void test() {
UserContext mockedContext = ...; // set user context
Context.current().withValue(Constant.USER_CONTEXT, mockedContext)
.run(() -> {
// testing code, call service rpc method
});
}
What is the proper way to set Context in tests without interceptors to use it their mocked values in GrpcService without nulls?
The problem is unrelated to which thread is used for execution. Context.run() runs within the current thread. And RouteGuideServerTest already uses serverBuilder.directExecutor() to have the service run within the test thread.
The problem is that the server has its own root Context it uses for inbound RPCs, separate from whatever Context happens to be on the current thread when being called. That requires an interceptor to change.
Related
I am having serious difficulties to understand how can I make some AsyncTask children, declared and instantiated in the Main Thread, to await for a Service child instance to reach some specific state.
As code examples here is the relevant part for Service; this code does what expected: receives the JSON response and holds it.
public class MyService extends Service {
private boolean received = false;
private string url = "http://someserver.mine/get-data-in-json-format";
// [...]
#Override
public void onCreate() {
doHttpJsonQuery();
}
public boolean responseReceived() {
return this.received;
}
public List<MyModel> getResponseAsObject() {
if (!this.received) return new ArrayList<MyModel>;
// Many code lines that convert the data into a list.
// [...]
return the_list;
}
// [...]
private void doHttpJsonQuery() {
OkHttpClient client = new OkHttpClient.Builder()
.build();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
call.cancel();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
}
});
this.received = true;
}
}
This Service works; fine. Then, from another class (which purpose will be to handle persistence inserting the received data in a local Room Database), I try to do the following (here's where my mind is blown):
public class DataRepository {
private MyRoomDatabase db;
private MyModelDao mModelDao;
// I'm skipping irrelevant code on purpose
// [...]
public DataRepository(Application application) {
db = MyRoomDatabase.getDatabase(application);
mModelDao = db.myModelDao();
// [...]
// Here I instance a subclass of ContextWrapper(i named it RemoteDataSource) which
// responsability will be handling different Services for making HTTP operations
mRemoteDataSource = new RemoteDataSource(application.getApplicationContext());
// It holds a reference to MyService. It has some public methods, like this one, to
// control the referenced Service from outside with some encaspsulation
mRemoteDataSource.startMyService();
// Instantiating a private nested class...
PopulateDbAsync mPopulateDbAsync = new PopulateDbAsync(db);
mPopulateDbAsync.doInBackground();
}
// [...]
// Here is the failing code
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
PopulateDbAsync(MyRoomDatabase db) {}
#Override
protected Void doInBackground(final Void... params) {
MyService mService = mRemoteDataSource.getMyService();
if (mService == null) {
// This doesn't happen at all right now...
Log.e("MY_ERROR","DataRepository.PopulateDbAsync --> MyService from RemoteDataSource is NULL!!!!");
}
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtain the NullReferenceException here.
// I am confused about how would I avoid this flaw in my code
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
}
Summarizing: my problem is that I will always get NullReferenceException in this line:
for (MyModel i_model : the_list) {
I am not familiar with multithreading, asyncronous operations and concurrent execution. I have been reading, for two weeks, lots of different documents on the Internet both from Android Official Website and from other websites as well, trying to figure it out... "AsyncTask is not good to perform this kind of operations"... so, what infrastructure should I implement, I have been wondering... should I use Handlers, Threads, Messengers, or what? The more I read, the more confused I get. It's like I have an Analysis Paralysis issue...
Most of the examples I find out there provide too verbose code examples on how to implement multithreading and concurrent execution; while I read them and try to figure out how to implement those structures in my code, I just get stuck; also, with so many classes to choose, I get even more confused...
Due to the HTTP call will need to be performed asyncronously (and response time will not always be the same), I am trying to figure out how to make the piece of code that throws the NullReferenceException "wait" for MyService to complete it's job before starting it's execution; while loops will not work due to it would break Main Thread's lifecycle. "Knowing" if the Service completed it's task or not would be as simple as using the boolean method responseReceived. The big idea is, every time new data is obtained through HTTP, updating the RoomDatabase with it, and, meanwhile, MainActivity would be showing the current local data (if any, or an empty list if there's nothing yet).
So, when I get it, I will understand how to refactor the whole code structure properly to start adding more Service child instances into my RemoteDataSource class, which I created with the idea of having all Service childs that will use OkHttp to perform HTTP communications, wrapped together in a single class for better organization.
What would be the proper way to achieve what I am looking for about this? Would someone be able to provide some short example explaining the code structure I will need for something like this? Examples with empty blocks containing comments like "code to execute when ready here" would be great so I can figure it out.
The question exposed here is related with the same project that made me post this other question some weeks ago; I have been reading here and there, performing some trial-and-error and correcting some code issues here-and-there since then; however, I am making a different question here; finding an answer for this would probably be the first step towards figuring out an answer to the other question as well.
URL References to documentation I have been reading
Some of the documentation I have been reading (but not limited to):
AsyncTask class documentation
Handler class documentation
Basics on Multithreading
Introduction to background processing in Android - Tutorial
Thread With Handlers - Android Example
Messenger class documentation
Well problem is with your application logic as follows,
If you are using AsyncTask that is obviously a separate thread from the main thread. But syncing to your database after retrieving data via HTTP call is a process which has a sequence ( Call through HTTP and retreive -> then persist to database ), it cannot perform asynchronously. So when you call,
List<MyModel> the_list = mService.getResponseAsObject();
this call happens in a particular thread and the program flow is in a different thread.
Since these are asynchronous tasks, they work asynchronously. which means you will never know which one will execute first and which one is next. But as per your logic,
if (the_list == null) {
this part essentially need the_list to be initialized to run. But the problem is at that point, service thread has not finished his work to perform your next logic. so its obvious breaking.
Better if you can re-design this so that you wait for the HTTP request to complete and then persist to database. Because suppose if your HTTP request complets first but still it returns you null or whatever not-desired output. So in that case you need to handle it in your logic.
OK so let me tell you a quick workaround.
Lets use just one thread instead of different threads. So consider changing following line
private class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
to
private class PopulateDbAsync
then you will get an error with
#Override
protected Void doInBackground(final Void... params) {
since we no longer extend AsyncTask class.
so change it as follows, by removing #Override
public Void doInBackground(final Void... params) {
This should fix the stated problem here.
I found a solution: creating custom listeners.
Steps to create a custom listener
1. Define an interface as an event contract with methods that define
events and arguments which are relevant event data.
2. Setup a listener member variable and setter in the child object which can be assigned an implementation of the interface.
3. Owner passes in a listener which implements the interface and handles the events from the child object.
4. Trigger events on the defined listener when the object wants to communicate events to it's owner
I got the NullReferenceException because MyService didn't finish it's job yet. So, first I create the listener's structure within MyService class like this (steps 1 and 2):
private MyServiceListener listener;
public interface MyServiceListener {
public void onDataDownloaded();
}
public void setMyServiceListener(MyServiceListener listener) {
this.listener = listener;
}
And, within the HTTP request's callback (step 4):
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
//...and some code to hold data as JSONArray
//[...]
// XXX Trigger the custom event
if (listener != null) {
listener.onDataDownloaded();
}
}
Now, I just can wrap the code that triggered the NullReferenceException within the custom listener like this (step 3):
// Within DataRepository class
mService.setMyServiceListener(new MyService.MyServiceListener) {
#Override
public void onDataDownloaded() {
List<MyModel> the_list = mService.getResponseAsObject();
if (the_list == null) {
// HERE! I obtainED the NullReferenceException here.
Log.e("MY_ERROR", "DataRepository.PopulateDbAsync --> error: response isn't ready yet.");
}
for (MyModel i_model : the_list) {
Log.d("MY_LOG", "DataRepository.PopulateDbAsync --> Inserting data in local DB...");
mModelDao.insert(i_model);
}
return null;
}
}
Actually, the real implementation required to nest this code example into another custom listener following similar steps; but this worked for me.
I am having thoughts on how do I write a test case for this using mockito.
Example, part of my logic in my main thread is to create a thread that does 3 things.
Please see my annotated code below.
Now the RequestThread can be spawn many times depending on the number of inputs coming from the main program.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread implements Runnable{
private final String request;
public RequestThread(String request) {
this.request = request;
}
#Override
public void run() {
//1. Instantiate a service passing the required request parameter
MyDataWebService service = new MyDataWebService(request);
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("/someDir/" + request);
Files.write(file, dataList, Charset.forName("UTF-8"));
}
}
}
My issue is this, I could not figure out how to properly write a JUnit/Mockito test for a threaded class.
I am not that well verse on Mockito and JUnit in general so I am looking for a way to unit test
a threaded application.
Can somebody guide me on how can I unit test such thing?
You need to bring some changes to your code in order to make it more testing-friendly. In particular:
Objects that you want to mock should implement an interface
Do not instantiate objects to mock in the function that you want to test
Here is a rewrite of the classes so that you can mock MyDataWebService and test RequestThread. Based on this example you will more easily be able to write a full test for the MainThreads class.
public class MainThreads {
public static void main(String[] args) {
RequestThread rt = new RequestThread("sample");
rt.start();
//RequestThread another = new RequestThread("sample-2");
//another.start();
//RequestThread newThread = new RequestThread("sample-3");
//newThread.start();
}
public static class RequestThread extends Thread {
private final String request;
// One important thing to note here, "service" has to be non-final. Else mockito won't be able to inject the mock.
private MyDataWebServiceInterface service;
public RequestThread(String request) {
this.request = request;
//1. Instantiate a service passing the required request parameter
// => do it in constructor, or passed as parameter, but NOT in the function to test
service = new MyDataWebService(request);
}
#Override
public void run() {
//2. Get the returned data
List<String> dataList = service.requestData();
//3. Write to file
Path file = Paths.get("someDir/" + request);
try {
Files.write(file, dataList, Charset.forName("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The interface & implementation for MyDataWebService:
interface MyDataWebServiceInterface {
List<String> requestData();
}
class MyDataWebService implements MyDataWebServiceInterface {
public MyDataWebService(String request) {
}
#Override
public List<String> requestData() {
return Arrays.asList("foo", "bar");
}
}
And a test using mockito. Note, the checks for existing file and thread sleeping may not be the most elegant thing to do here. If you can afford adding some marker in RequestThread to indicate that the data has been written, it would certainly make the test better and safer (filesystems i/o are sometimes tricky to test).
#RunWith(MockitoJUnitRunner.class)
public class RequestThreadTest {
private static final Path FILE = Paths.get("someDir", "sample");
#Mock
MyDataWebServiceInterface service;
#InjectMocks
MainThreads.RequestThread reqThread = new MainThreads.RequestThread("sample");
#Before
public void setup() throws IOException, InterruptedException {
if (Files.exists(FILE)) {
Files.delete(FILE);
while (Files.exists(FILE)) {
Thread.sleep(50);
}
}
}
#Test
public void shouldWriteFile() throws InterruptedException {
Mockito.when(service.requestData()).thenReturn(Arrays.asList("one", "two"));
reqThread.start();
while (!Files.exists(FILE)) {
Thread.sleep(50);
}
// HERE run assertions about file content
}
}
Now, testing asynchronous code is often more complicated than synchronous because you will often face non-determinist behaviours, timing issues, etc. You may want to set a timeout on your test, but remember: continuous integration tools (jenkins, travis etc.) will often run slower than your machine, it's a common cause of problems, so don't set it too tight. As far as I know there is no "one-fits-all" solution for non-determinist issues.
There's an excellent article about non-determinism in tests by Martin Fowler: https://martinfowler.com/articles/nonDeterminism.html
A distinctive non-answer: in 2018, you don't use "raw" threads any more.
Java has much better abstractions to offer by now, for example the ExecutorService. And guess what: when you have your code submit tasks into such a service, you can probably test it using a same-thread executor service.
Meaning: by using such abstractions and dissecting your delivery into specific services, you might be able to (almost) fully test not only the small units, but also how tasks come into your system and worked on.
In other words: you unit test your "tasks", then you "unit" test the integration of tasks when they go into such an executor. Then you are only left with a bit of real function/integration testing to check that the "true parallel" solution behaves as expected.
Anything else gets complicated quickly. Using real threads in ordinary unit tests can lead to inconsistent behavior, or increased runtimes (like the test waiting for threads to asynchronously doing something).
As in your example: your test would simply sit there and regularly check if the expected file was written with the expected content. Leading to: how long should it wait before failing? Waiting not long enough means that your test will occasionally fail because code sometimes just takes longer. If you wait too long, that adds up to the overall time you need to run your tests. You don't want to end up with hundreds of unit tests were some need 10, 20 seconds because "waiting for other threads".
I am developing a Java Request Sampler with JMeter by extending AbstractJavaSamplerClient. The test goes like this:
public class JmeterTest extends AbstractJavaSamplerClient {
public void setupTest(JavaSamplerContext context) {
System.out.println("Test setup");
}
public SampleResult runTest(JavaSamplerContext context) {
SampleResult result = new SampleResult();
System.out.println("Test..");
result.setSuccessful(true);
result.setResponseData("Success");
}
public void teardownTest(JavaSamplerContext context) {
System.out.println("Test cleanup");
}
}
I created a jar out of this test class and pointed it through the JMeter UI (through Java Request Sampler). The problem in my case is when I run the test with 5 users, the setUpTest & tearDownTest methods gets called for every user as per design.
Is there any setting where the setUp and Cleanup methods get called only once for all threads in the thread group. My requirement is to do setup and cleanup only once for all threads.
Here are the options you can try out:
Perform setUp actions separately in setUp Thread Group
Perform setUp actions separately in the same Thread Group. Put setUp logic under the If Controller and use ${__BeanShell(vars.getIteration() == 1)} as condition
Modify your code like:
public void setupTest(JavaSamplerContext context) {
if (JMeterContextService.getContext().getVariables().getIteration() == 1) {
System.out.println("Test setup");
}
}
Both points 2 and 3 assume that setUp code will be executed only during first iteration of your test by each thread. Remember that JMeterVariables.getIteration() number is incremented only when Thread Group-level loops occur.
I am trying to write an Instrumentation Test for my Android app.
I'm running into some weird threading issues and I can't seem to find a solution.
My Original Test:
#RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {
#Rule
public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);
#Test
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
}
This resulted in an
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
...
com.kwtree.kwtree.workorder.WorkOrderDetails.updateDetails(WorkOrderDetails.java:155)
The only thing the updateDetails() method does is some setText() calls.
After researching a bit, it seemed like adding a UiThreadTestRule and android.support.test.annotation.UiThreadTest annotation to my test would fix the problem.
#UiThreadTest:
#RunWith(AndroidJUnit4.class)
public class WorkOrderDetailsTest {
//Note: This is new
#Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
#Rule
public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class);
#Test
#UiThreadTest //Note: This is new
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
}
java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main)
(Note: All of the methods in this stack trace are not my code)
It seems to be giving me mixed results... If it needs to be run on the original thread that created the views but can't run on the main thread, what thread should it be run on?
I'd really appreciate any help or suggestions!
Those instrumentation tests run inside their own app. This also means, they run in their own thread.
You must think of your instrumentation as something you install alongside your actual app, so your possible interactions are 'limited'.
You need to call all view methods from the UIThread / main thread of the application, so calling activity.updateDetails(workOrder); from your instrumentation thread is not the application main thread. This is why the exception is thrown.
You can just run the code you need to test on your main thread like you would do if you were calling it inside your app from a different thread by using
activity.runOnUiThread(new Runnable() {
public void run() {
activity.updateDetails(workOrder);
}
}
With this running your test should work.
The illegal state exception you are receiving seems to be because of your interaction with the rule. The documentation states
Note that instrumentation methods may not be used when this annotation is present.
If you start / get your activity in #Before it should also work.
You can run portion of your test on the main UI thread with the help of UiThreadTestRule.runOnUiThread(Runnable):
#Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
#Test
public void loadWorkOrder_displaysCorrectly() throws Exception {
final WorkOrderDetails activity = activityRule.getActivity();
uiThreadTestRule.runOnUiThread(new Runnable() {
#Override
public void run() {
WorkOrder workOrder = new WorkOrder();
activity.updateDetails(workOrder);
}
});
//Verify customer info is displayed
onView(withId(R.id.customer_name))
.check(matches(withText("John Smith")));
}
In most cases it is simpler to annotate the test method with UiThreadTest, however, it may incur other errors such as java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main).
FYR, here is a quote from UiThreadTest's Javadoc:
Note, due to current JUnit limitation, methods annotated with Before and After will also be executed on the UI Thread. Consider using runOnUiThread(Runnable) if this is an issue.
Please note UiThreadTest (package android.support.test.annotation) mentioned above is different from (UiThreadTest (package android.test)).
The accepted answer is now deprecated
The easiest way to achieve this is simply using UiThreadTest
import android.support.test.annotation.UiThreadTest;
#Test
#UiThreadTest
public void myTest() {
// Set up conditions for test
// Call the tested method
activity.doSomethingWithAView()
// Verify that the results are correct
}
With the androidx test runner a new class was added UiThreadStatement that gives a runOnUiThread method for this.
UiThreadStatement.runOnUiThread {
// call activity here
}
The accepted answer describes what is going on perfectly.
As an addition, in case someone is curious why Espresso's methods that touch the UI e.g. perform(ViewActions ...) don't need to do the same, it is simply because they end up doing it later for us.
If you follow perform(ViewActions ...) you will find it ends up doing the following (in android.support.test.espresso.ViewInteraction):
private void runSynchronouslyOnUiThread(Runnable action) {
...
mainThreadExecutor.execute(uiTask);
...
}
That mainThreadExecutor is itself annotated with #MainThread.
In other words, Espresso also needs to play by the same rules described by David on the accepted answer.
I have the folowing constructor...
#Inject
public EditorPresenter(final EventBus eventBus, final MyView view, final Provider<DataProvider> provider) {
DataProvider provider = provider.get();
provider.getInitData().fire(new Receiver<List<DataElement>>() {
#Override
public void onSuccess(List<DataElement> response) {
LOG.info("seting feed types to {}", response);
EditorPresenter.this.data = response;
}
});
}
This constructor sets the class field data to the values returned in the request factory call.
The problem is this data requires a call to the server and is thus asynchronous.
And this field needs to be set when the constructor returns as other objects/beans depend on it (I'm having subsequent errors that depend on data being initalised).
What is the most efficient and light weight way of handling this scenario with Gin?
I'm hoping that there is something built into GIN that handles this scenario gracefully.
GQuery Promise solves this kind of situations:
Something like:
public void yourMethod(....) {
....
getDataFromServer(provider).then(processData)
.done(new Function() { public void f(){
continueYourFlow();
}})
.fail(new Function() { public void f(){
handleError();
}});
}
protected Promise getDataFromServer(final Provider<DataProvider> provider) {
return new PromiseRF(provider.getInitData());
}
Function proccessData = new Function() { public void f() {
List<DataElement> data = arguments(0);
//do something with your data
}};
should work. If not, just ask!
There is something wrong in your approach. You shouldn't hold all your application waiting for server.
If I understand, some data from server is required before client is initialized. Maybe you should put them in your host page? Or move initialization of presenters to other methods and execute these methods by events.
It might be best to not initialize the rest of your app yet. I'm not sure how your initialization is laid out, but I would not initialize anymore after you inject the instance of your EditorPresenter class.
When your onSuccess call gets triggered, fire an event or call a method that picks up where you would have left off. If you think it will be a while you could throw up a wait screen or some such.