Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Single.just(Void)

I am writing some unit test cases for my application. I want to mock MongoClient update method, but the update returns Single<Void>.

when(mongoClient.rxUpdate(anyString(), any(JsonObject.class), any(JsonObject.class)))
.thenReturn(Single.just(Void))

Now Single.just(Void) doesn't work, what is the correct way of doing it?


--UPDATE--

So I am writing unit test for updateUserProfile method and for that I have mocked service. But the service.updateAccount method return is something I am not able to mock.

//Controller class
public void updateUserProfile(RoutingContext routingContext){
        // some code
    service.updateAccount(query, update)
            .subscribe(r -> routingContext.response().end());
}

//Service Class
public Single<Void> updateAccount(JsonObject query, JsonObject update){
    return mongoClient.rxUpdate("accounts", query, update);
}

Because the return type of mongoClient.rxUpdate is Single<Void>, I am not able to mock that part.

For now the workaround which I have figured out is:

public Single<Boolean> updateAccount(JsonObject query, JsonObject update){
    return mongoClient.rxUpdate("accounts", query, update).map(_void -> true);
}

But this is just a hacky way of doing it, I want to know how can I exactly create Single<Void>

like image 535
Minato Namikaze Avatar asked Feb 01 '18 05:02

Minato Namikaze


1 Answers

Having a method returning Single<Void> may raise some concerns, as some users have already expressed their view on this in the comments.

But if you are stuck with this and you really need to mock it (for whatever reason), there are definitely ways to create a Single<Void> instance, for example you could use the create method of the Single class:

Single<Void> singleVoid = Single.create(singleSubscriber -> {});

when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleVoid);

Single<Void> result = test.updateAccount(null, null);

result.subscribe(
        aVoid -> System.out.println("incoming!") // This won't be executed.
);

Please note: you won't be able to actually emmit a Single item, since Void can't be instantiated without reflection.

A trick that could eventually work in some cases is to ommit the generic type argument and emmit an Object instead, but this could lead easily to a ClassCastException. I would not recommend to use this:

Single singleObject = Single.just(new Object());

when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleObject);

Single<Void> result = test.updateAccount(null, null);

// This is going to throw an exception:
// "java.base/java.lang.Object cannot be cast to java.base/java.lang.Void"
result.subscribe(
        aVoid -> System.out.println("incoming:" + aVoid)
);

And of course you could use reflection as well (as already suggested by Minato Namikaze):

Constructor<Void> constructor = Void.class.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
Void instance = constructor.newInstance();

Single<Void> singleVoidMock = Single.just(instance);

when(test.updateAccount(any(JsonObject.class), any(JsonObject.class))).thenReturn(singleVoidMock);

Single<Void> result = test.updateAccount(null, null);

result.subscribe(
        aVoid -> System.out.println("incoming:" + aVoid) // Prints: "incoming:java.lang.Void@4fb3ee4e"
);
like image 108
Attila Avatar answered Nov 27 '22 01:11

Attila