Test that RxJava BehaviorProcessor emits a value - java

I'm having trouble understanding why all those processors pass the test but Behavior does not:
package com.example;
import org.junit.Test;
import io.reactivex.Flowable;
import io.reactivex.processors.*;
public class ProcessorTest {
private static Flowable<String> justFoo() {
return Flowable.just("foo");
}
private static FlowableProcessor<String> subscribeToFoo(
FlowableProcessor<String> processor) {
justFoo().subscribe(processor);
return processor;
}
#Test public void flowable() { // pass
justFoo().test().assertValue("foo");
}
#Test public void async() { // pass
subscribeToFoo(AsyncProcessor.create()).test().assertValue("foo");
}
#Test public void replay() { // pass
subscribeToFoo(ReplayProcessor.create()).test().assertValue("foo");
}
#Test public void unicast() { // pass
subscribeToFoo(UnicastProcessor.create()).test().assertValue("foo");
}
#Test public void behaviorFail() { // fail
subscribeToFoo(BehaviorProcessor.create()).test().assertValue("foo");
}
#Test public void behaviorPassing() { // pass
subscribeToFoo(BehaviorProcessor.create())
.test()
.assertNoValues()
.assertSubscribed()
.assertComplete()
.assertNoErrors()
.assertNoTimeout()
.assertTerminated();
}
}
The docs say that BehaviorProcessor is a:
Processor that emits the most recent item it has observed and all subsequent observed items to each subscribed Subscriber.
So in my understanding it should pass the behaviorFail test, not the behaviorPassing. How come is that?
How would I write a valid test, to know that a BehaviorProcessor emitted a certain value?

Getting rid of the terminal event passed to the processor would help:
#Test public void behavior() {
final BehaviorProcessor<String> processor = BehaviorProcessor.create();
justFoo().concatWith(Flowable.never()).subscribe(processor);
processor.test().assertValue("foo");
}

Related

mockito mock static function does not work if the function is called in a Thread

android app, a java class needs to do something based on the NotificationManager's status.
class Util {
static void setupByPermission(#NonNull final Context appContext) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
NotificationManagerCompat nm = NotificationManagerCompat.from(appContext); // should got from stub
boolean overallPermission = currentNotificationsPermission(nm);
if (overallPermission) {
doWithPermission();
} else {
doWithoutPermission();
}
} catch (Throwable ex) {}
}
});
t.start();
}
static boolean currentNotificationsPermission(#NonNull NotificationManagerCompat nm) {
System.out.println("+++ enter currentNotificationsPermission("+nm+")");
boolean overallPermission = nm.areNotificationsEnabled();// should got result from stub
System.out.println("+++ ========= in currentNotificationsPermission("+nm+"), nm.areNotificationsEnabled() ==> "+overallPermission);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (overallPermission) {
List<NotificationChannel> channels = nm.getNotificationChannels();
boolean someChannelEnabled = channels.isEmpty();
for (NotificationChannel channel : channels) {
if (channel.getImportance() != NotificationManagerCompat.IMPORTANCE_NONE) {
someChannelEnabled = true;
break;
}
}
overallPermission = overallPermission && someChannelEnabled;
}
}
System.out.println("+++ --- exit =========== currentNotificationsPermission(), overallPermission:"+overallPermission);
return overallPermission;
}
}
would like to stub the NotificationManagerCompat.areNotificationsEnabled()
to force a test with the return of either true or false.
test using mockito-inline 3.8.0
#Test
public void test () throws Exception {
try (MockedStatic<NotificationManagerCompat> nmMoc = Mockito.mockStatic(NotificationManagerCompat.class);
MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)
) {
NotificationManagerCompat nmSpy = spy(NotificationManagerCompat.from(application));
when(nmSpy.areNotificationsEnabled())
.thenReturn(false); //or true
nmMoc.when(() -> NotificationManagerCompat.from(any(Context.class)))
.thenReturn(nmSpy);
// test
final CountDownLatch latch = new CountDownLatch(1);
utilMoc.setupByPermission(application);
latch.await(2, TimeUnit.SECONDS);
Mockito.verify(......);
}
}
but the stub is not called when they are in the Thread. same if stub the currentNotificationsPermission().
Hot to make the stub for a static function to work in the the thread?
There seem to be a few things wrong with your test:
Don't mock static methods. Refactor your code to use an interface and an implementation. This will make dependency injection easier too.
Read the Javadoc for MockedStatic. It explicitly tells you that the mock works only on the original thread.
How does your code compile? utilMoc is a MockedStatic<Util> so how can you call setupByPermission on it?
Given that you've mocked Util, calling methods on Util will not call the 'real' method anyway, unless you tell it to. See the example below.
Unit testing multithreaded code is difficult. Have a component which is responsible for executing Runnable. In your tests use a dummy implementation which runs the Runnable on the current thread.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
#ExtendWith(MockitoExtension.class)
public class TestExample {
public static class Foo {
public static String bar() {
return "bar";
}
}
#Test
public void aTest() {
try (MockedStatic<Foo> foo = Mockito.mockStatic(Foo.class)) {
// without this line Foo.bar() will return null
when(Foo.bar()).thenCallRealMethod();
assertThat(Foo.bar()).isEqualTo("bar");
}
}
}
While people have put in a lot of work to make it possible to mock static methods, as you're seeing it still isn't straightforward. The refactoring needed to avoid it is straightforward and has other benefits.

How do I test Function's code when it's passed as method parameter?

Is it possible to test code that is written in lambda function that is passed inside the method process?
#AllArgsConstructor
public class JsonController {
private final JsonElementProcessingService jsonElementProcessingService;
private final JsonObjectProcessingService jsonObjectProcessingService;
private final JsonArrayProcessingService jsonArrayProcessingService;
public void process(String rawJson) {
jsonElementProcessingService.process(json -> {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}, rawJson);
}
}
Since the lambda is lazy the function is not invoked (Function::apply) when I call JsonController::process so is there any way to check that jsonArrayProcessingService::process is called?
#RunWith(JMockit.class)
public class JsonControllerTest {
#Injectable
private JsonElementProcessingService jsonElementProcessingService;
#Injectable
private JsonObjectProcessingService jsonObjectProcessingService;
#Injectable
private JsonArrayProcessingService jsonArrayProcessingService;
#Tested
private JsonController jsonController;
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
// how check here that jsonArrayProcessingService was invoked?
}
}
Just make it testable (and readable) by converting it to a method:
public void process(String rawJson) {
jsonElementProcessingService.process(this::parse, rawJson);
}
Object parse(String json) {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}
The relevant guiding principles I personally follow are:
anytime my lambdas require curly brackets, convert them to a method
organise code so that it can be unit tested
You may need to change the return type of the parse method to match whatever your processing services (which you didn’t show) return.
Given its relatively-basic redirection logic, don't you just want to confirm which of the #Injectables got called:
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
new Verifications() {{
jsonArrayProcessingService.process(withInstanceOf(JsonArray.class));
}};
}

TestNG dependsOnMethods

package test;
import org.testng.annotations.Test;
public class Day3 {
#Test
public void webLoginCarLoan() {
System.out.println("WebLoginCarLoan");
}
#Test
public void mobileLoginCarLoan() {
System.out.println("MobileLoginCarLoan");
}
#Test
public void mobileSignoutCarLoan() {
System.out.println("MobileSignoutCarLoan");
}
#Test(dependsOnMethods = { "webLoginCarLoan" })
public void apiCarLoan() {
System.out.println("LoginAPICarLoan");
}
}
Output:
MobileLoginCarLoan
WebLoginCarLoan
MobileSignoutCarLoan
LoginAPICarLoan
Why WebLoginCarLoan comes before MobileSignoutCarLoan in Output?
TestNG does not execute tests in same order as noted in class. If you think, need to execute tests/#Test methods in specified order then use priority
#Test(priority=1)
Also as pointed by Mark "I think that dependsOnMethods will make sure webLoginCarLoan is executed before apiCarLoan however not immediately after it perse"
see in Java Doc https://jitpack.io/com/github/cbeust/testng/master/javadoc/org/testng/annotations/Test.html#dependsOnMethods--

Testing class that insert, update and delete from the db

I have class that has 3 methods: insert, update and delete from the db.
In order to test it in the insert test method I need to use the insert method and after I insert i need to delete what I inserted, but in order to delete I should use the delete method that I also want to test so it didn't make sense to me that I need to use them and also test them.
I hope you understand my problem. Thanks in advance!
You must decide what you want to test. That was you describe, it is an integration test. By a “real” unitTest, you test only your method, and not the System method and not the database.
If you want a unitTest, you have several options. For Example, you work with interfaces and catch your statement before it comes to the database.
Edit 1 - one possibility to implement unit test with interfaces:
You need one interface that implements the method these go to the backend system:
public interface IDatabase{
public returnValue insert(yourParam);
public int update(yourParam);
}
Then you implement your method with the real functions in a class:
public class Database implements IDatabase {
#Override
public returnValue insert(yourParam) {
// do something
return null;
}
#Override
public int update(yourParam){
// do something
return 0;
}
}
This class you call in the main class:
/**
* The real class to do what you want to do.
*/
public class RealClass {
private IDatabase dbInstance = null;
private IDatabase getDbInstance() {
if (dbInstance == null) {
dbInstance = new Database();
}
return dbInstance;
}
protected void setDbInstance(IDatabase dataBase) {
dbInstance = dataBase;
}
public static void main(String[] args) {
getDbInstance().insert(yourParam);
}
}
For the unit test you implement the interface again:
public class UnitTest implements IDatabase {
#Override
public returnValue insert(yourParam) {
// Here can you test your statement and manipulate the return value
return null;
}
#Override
public int update(yourParam){
if (yourParam.containsValue(value1)) {
assertEquals("yourStatement", yourParam);
return 1;
}else if (yourParam.containsValue(value2)) {
assertEquals("yourStatement2", yourParam);
return 5;
}else{
assertTrue(false,"unknown Statement")
}
}
#Test
public void yourTest(){
RealClass.setDbInstance(this);
//Test something
}
}
This is time-consuming to implement, but with this, you are independent from the backend system and you can call the unittest every time without a database.
By default, the order of test methods is not warrantied in JUnit. Nevertheless, as of JUnit 4.11, you can order by the test name, as follows:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Test1 {
#Test
public void aInsert() {
System.out.println("first INSERT");
}
#Test
public void bUpdate() throws Exception {
System.out.println("second UPDATE");
}
#Test
public void cDelete() throws Exception {
System.out.println("third DELETE");
}
}

Jmock unexpected method invocation, cannot see why

I have the following method....
public void testa(Car car) {
em.persist(car);
car.setEngine(null);
}
in my test i have:
protected final Car mockCar = context.mock(Car.class);
#Test
public void testCar() {
context.checking(new Expectations() {
{
oneOf(em).persist(car);
oneOf(car).setEngine(null);
}
});
this.stacker.testa(mockCar);
context.assertIsSatisfied();
}
I run this and i keep getting :
unexpected invocation car.setEngine(null)...
If i remove the code that sets the engine in the code and from the test the tests passes... im totally confused as to why this is happening...
exception:
java.lang.AssertionError: unexpected invocation: car.setEngine(null)
no expectations specified: did you...
- forget to start an expectation with a cardinality clause?
- call a mocked method to specify the parameter of an expectation?
Your problem appears to be that you have two Car objects. You have a car, which you set the expectations on, and a mockCar, which you pass through. Without seeing the definitions of these objects, I can't say for sure, but this is probably the root of your problem.
If this isn't the issue, we're going to need more code. Preferably the entire file(s).
For reference, this compiles fine and passes the tests:
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Test;
public class TestyMcTestTest {
private final Mockery context = new Mockery();
private final EntityManager em = context.mock(EntityManager.class);
private final Stacker stacker = new Stacker(em);
private final Car mockCar = context.mock(Car.class);
#Test
public void testCar() {
context.checking(new Expectations() {{
oneOf(em).persist(mockCar);
oneOf(mockCar).setEngine(null);
}});
this.stacker.testa(mockCar);
context.assertIsSatisfied();
}
public interface Car {
void setEngine(Engine engine);
}
public interface Engine { }
public class Stacker {
private final EntityManager em;
public Stacker(EntityManager em) {
this.em = em;
}
public void testa(Car car) {
em.persist(car);
car.setEngine(null);
}
}
private interface EntityManager {
void persist(Object o);
}
}

Categories

Resources