How do I unit test RxJava Completable doOnSuccess function? - unit-testing

I have seen how to test observable using TestSubscriber but I have no idea how to test Completable.doOnSuccess callback. Specifically this method:
fun setAuthToken(authToken: AuthToken): Completable {
this.authToken = authToken
return Completable.fromSingle<User>(api
.getCurrentUser()
.doOnSuccess {
user = it
})
}

This is not something that might not need to be tested with RxJava test subscribers at all (depending on the rest of the code).
Remember - you don't want to test internal state, or at least do it as rarely as possible. Internal state and class structure can change and it will probably change often. So it's bad practice to check if user is assigned to the field.
So you could make Completable blocking and then assert state of (let’s call it ‚server’) server class, but I would highly discourage doing it this way:
server.setAuthToken(AuthToken("token"))
.blockingAwait()
assertThat(server.user, equalTo(expectedUser))
What you want to test is behavior.
You are probably not assigning user to the field just for the sake of having some fields. You are doing it to use information from user later on. So first you should call setAuthToken and then call function that really uses information from the user. Then you can assert if used information is correct and is coming from correct user.
So sample tests (depending on the class) could look like this:
server.setAuthToken(AuthToken("token"))
.andThen(server.sendRequest())
.blockingAwait()
// assert if correct user info was sent
or
server.setAuthToken(AuthToken("token"))
.andThen(server.sendRequest())
.test()
// assert if correct user info was sent

Related

Accessing request container (event_dispatcher) within a test client

I created a simple test case in Symfony.
So one client which should listen for an event which will be dispatched during an request.
But nothing happen because the request have an own scope or I dont know why Im not able to access the dispatcher in it.
$this->client = static::createClient();
self::$container = $this->client->getContainer();
$dispatcher = self::$container->get('event_dispatcher');
$dispatcher->addListener('example', function ($event) {
// Never executed
});
$this->client->request('POST', $endpoint, $this->getNextRequestParameters($i), [$file], $this->requestHeaders);
$this->client->getResponse();
The listener is never called.
When I debug it a bit I find out that the object hash via spl_object_hash($dispatcher) is different on the highest level than on within the request level.
So it seems that the request has an own world and ignores everything outside.
But then is the question how I can put my listener to this "world"?
I think part of the problem is the mixing of testing styles. You have a WebTestCase which is intended for a very high level of testing (requests & responses). It should not really care about internals, i.e. which services or listeners are called. It only cares that given input x (your request) you will get output y (your response). This allows to ensure the basic functionality as perceived by your users is always met, without caring how it is done. Making these tests very flexible.
By looking into the container and the services you are going into a lower level of testing, which tests interconnected services. This is usually only done within the same process for the reasons you already found out. The higher level test has 2 separate lifecycles, one for the test itself and one for the simulated web request to your application, hence the different object ids.
The solution is either to emit something to the higher level, e.g. by setting headers or changing the output, so you can inspect the response body. You could also write into some log file and check the logs before/after the request for that message.
A different option would be to move the whole test into a lower level where you do not need the requests and instead only work with the services. For this you can use the KernelTestCase (instead of the WebTestCase) and instead of calling createClient() you call bootKernel. This will give you access to your container where you can modify the EventDispatcher. Rather than sending a request you can then either call the code directly, e.g. dispatch an event if you only want to test the listeners, or you can make your controller accessible as service and then manually create a request, call the action and then either check the response or whatever else you want to assert on. This could look roughly like this:
public function testActionFiresEvent()
{
$kernel = static::bootKernel();
$eventDispatcher = $kernel->getContainer()->get('event_dispatcher');
// ...
$request = Request::create();
// This might not work when the controller
// You can create a service configuration only used by tests,
// e.g. "config/services_test.yaml" and provide the controller service there
$controller = $kernel->getContainer()->get(MyController::class);
$response = $controller->endpointAction($request);
// ...Do assertions...
}

Mockito, TooManyActualInvocations when testing conditions Spek Framework

For a scenario unit testing a user entering a password and password confirmation. when i try to verify the same method being called in a different on() block, i get the following error on the 2nd on()block.
org.mockito.exceptions.verification.TooManyActualInvocations:
activationPasswordView.disableButton();
Wanted 1 time:
But was twice
Here is the code:
given("user set password "){
on(“password is null”){
presenterImpl.validatePassword(null, null)
it("done button should be disabled"){
verify(view).disableButton()
}
}
on("input only one password"){
presenterImpl.validatePassword("Password", "")
it("done button should be disabled"){
verify(view).disableButton()
}
}
}
But if i call a different method, it works correctly. I assume this was not how Spek framework was intended to be used as all the examples i have seen always use an Assert. Is there a way i can write the following conditions in Spek without the error?. Even a different given() still causes the error.
The mocked object counts the number of times the function invoked for the specific mock.
Since you did not reset the mock between each test, the counter is increased each time you invoked the method.
You should use: reset(view) to reset the mocks counter.
This issue is not related to the Spek framework.

Mocking/stubbing whether or debug log is enabled?

How do I write a mock test that allows me to validate that an inaccessible property (debugLog) is set to true? Do I try to find a way to find the value of the property? Do I verify that console.debug is set? Does a spy make sense in this situation or should I use a stub?
Class X
let showDebugLogs = false,
debugLog = _.noop
/**
* Configures Class X instances to output or not output debug logs.
* #param {Boolean} state The state.
*/
exports.showDebugLogs = function (state) {
showDebugLogs = state;
debugLog = showDebugLogs ? console.debug || console.log : _.noop;
};
Unit Test
describe('showDebugLogs(state)', function () {
let spy;
it('should configure RealtimeEvents instances to output or not output debug logs', function () {
spy = sinon.spy(X, 'debugLog');
X.showDebugLogs(true);
assert.strictEqual(spy.calledOnce, true, 'Debug logging was not enabled as expected.');
spy.restore();
});
});
Mock testing is used for "isoloting" a class under test from its environment to decrease its side effects and to increase its test-ability. For example, if you are testing a class which makes AJAX calls to a web server, you'd probably do not want to:
1) wait for AJAX calls to complete (waste of time)
2) observe your tests fall apart because of possible networking problems
3) cause data modifications on the server side
and so on.
So what you do is to "MOCK" the part of your code, which makes the AJAX call, and depending on your test you either:
1) return success and response accompanying a successful request
2) return an error and report the nature of the point of failure to see how your code is handing it.
For your case, what you need is just a simple unit test case. You can use introspection techniques to assert internal states of your object, if this is what you really want to. However, this comes with a warning: it is discouraged. Please see Notes at the bottom
Unit testing should be done to test behavior or public state of an object. So, you should really NOT care about internals of a class.
Therefore, I suggest you to re-consider what you are trying to test and find a better way of testing it.
Suggestion: Instead of checking a flag in your class, you can mock up logger for your test. And write at least two test cases as follows:
1) When showDebugLogs = true, make sure log statement of your mock logger is fired
2) When showDebuLogs = false, log statement of your mock logger is not called.
Notes: There has been a long debate between two schools of people: a group advocating that private members/methods are implementation details and should NOT be tested directly, and another group which opposes this idea:
Excerpt from a wikipedia article:
There is some debate among practitioners of TDD, documented in their
blogs and other writings, as to whether it is wise to test private
methods and data anyway. Some argue that private members are a mere
implementation detail that may change, and should be allowed to do so
without breaking numbers of tests. Thus it should be sufficient to
test any class through its public interface or through its subclass
interface, which some languages call the "protected" interface.[29]
Others say that crucial aspects of functionality may be implemented in
private methods and testing them directly offers advantage of smaller
and more direct unit tests

How to unit test a method whose side effect is to call other method?

Here is my example:
void doneWithCurrentState(State state) {
switch (state) {
case State.Normal:
// this method is never actually called with State.Normal
break;
case State.Editing:
controller.updateViewState(State.Normal);
database.updateObjectWithDetails(controller.getObjectDetailsFromViews())
break;
case State.Focus:
controller.updateViewState(State.Editing);
break;
}
}
My controller calls the doneWithCurrentState when a specific button is pressed. The states are different positions on screen that the views for that controller can assume.
If the current state is Normal, the button will be hidden.
If the button is pressed with the current state as Editing, the doneWithCurrentState method (I say method because it is actually inside a class ``) will be called and it should change the controller's views state to Normal and update the Object in the database using the ObjectDetails (which is just a struct with data that will be used to update the Object) that should be retrieved from the controller's views (i.e., text fields, checkboxes, etc).
If the button is pressed with the current state as Focus, it should just send back to the Editing state.
I am unit testing it like this:
void testDoneWithCurrentStateEditing() {
mockController.objectDetails = ...;
myClass.doneWithCurrentState(State.Editing);
AssertEqual(mockController.viewState, State.Normal, "controller state should change to Normal");
AssertTrue(mockDatabase.updateObjectWithDetailsWasCalled, "updateObjectWithDetails should be called");
AssertEqual(mockDatabase.updatedWithObjectDetail, mockController.objectDetails, "database should be updated with corresponding objectDetails");
}
void testDoneWithCurrentStateFocus() {
myClass.doneWithCurrentState(State.Focus);
AssertEqual(mockController.viewState, State.Editing, "controller state should change to Editing");
AssertFalse(mockDatabase.updateObjectWithDetailsWasCalled, "updateObjectWithDetails should not be called");
}
But it seems wrong, it seems like I'm asserting a method call is made and then I'm making the call... it's just like asserting setter and getter methods.
What would be the right way of testing that doneWithCurrentState method?
As part of the answer, I do accept something like "first you should refactor the method to better separate these concerns...".
Thank you.
If you wrote this not test-first, an obvious way to write it would be to write one case, then copy-paste into the next case. An easy mistake to make in that case would be to forget to update the parameter to updateViewState(). So (for instance) you might find yourself going from State.Focus to State.Normal. The test you've written, although it may seem weak to you, protects against mistakes of that nature. So I think it's doing what it should.
First of all, please consider using state machine for your state transitions, you will get out of switch statement branching business, which will result in a great simplification of your tests.
Next, treat your tests as a potential source for code and design smells. If it is hard to write a test for a piece of code - probably the code is lacking quality (breaking SRP, too coupled, etc.) and can be simplified/improved.
void doneWithCurrentState(State state) {
State nextState = this.stateMachine.GetNextState(state);
controller.updateViewState(nextState);
if(nextState == State.Editing)
database.updateObjectWithDetails(controller.getObjectDetailsFromViews());
}
Then you can notice that you can pull out the call to the state machine of of the method and pass in the nextState.
//whoever calls this method should get nextState from state machine.
void doneWithCurrentState(State nextState) {
controller.updateViewState(nextState);
if(nextState == State.Editing)
database.updateObjectWithDetails(controller.getObjectDetailsFromViews());
}
and so forth.. you will write simple tests for state transitions in your state machine tests.. your overall code complexity gets down and all is goodness!? Well, there is hardly a limit to the level of goodness you can achieve and I can see multiple ways the code can be cleaned up even further.
As per your original question, how to test that code of your class makes a call on 'database' or 'controller' with proper parameters with specific state is passed in. You are doing it "right", that what mocks are meant to do. However, there are better ways. Consider event-based design. What if your controller could fire the events like "NextState" and your 'database' object can just subscribe to it? Then all your test needs to test is that the proper event is fired and not include anything about database (eliminating dependencies :))
I think Paul is spot on: put the state changes based on the incoming state into a state machine, i.e. an objects whose repsonsibility is to determine what comes next. This may sound dumb, because you kind of move the same code to another object, but at least this puts the controller on a diet. It shouldn't worry about too much details itself to be maintainable.
I worry about updateViewState, though. Why does it take the same kind of parameter as the controller's callback for user interaction? Can you model this differently? It's hard to tell you anything specific without looking at the flow of information (a detailed sequence diagram with comments might help), because usually the real insight into problems like these lies multiple levels deeper in the call stack. Without knowledge about the meaning of all this, it's hard to come up with a canned solution that fits.
Questions that might help:
if State represents 3 (?) user interactions which all go through the same tunnel, can you model the actions to take as Strategy or Command?
if doneWithCurrentState represents finishing one of many interaction modes, do you really need to use a shared doneWithCurrentState method? Couldn't you use three different callbacks? Maybe this is the wrong kind of abstraction. ("Don't Repeat Yourself" isn't about code but about things that change (in)dependently)

How to go about testing decision-state in Spring WebFlow

I'm trying to find the best way to unit test decision-states within a Spring WebFlow context.
<var name="registration" class="*some class path*.Registration"/>
<decision-state id="checkSignedIn">
<if test="*someClass*.isSignedOn(registration)"
then="checkHas*Said*Service"
else="registrationChoice"/>
</decision-state>
<decision-state id="checkHasTCloudService">
<if test="*someClass*Dao.isUserRegisteredFor*saidSvc*(registration)"
then="*svc*Activated"
else="registrationChoice"/>
</decision-state>
<view-state id="registrationChoice" model="registration" view="view.xhtml" >
<on-entry>...
N.B. the someClass and the someClassDao are not within the FlowScope or ConversationScope.
I want to test, via Mockito, that the decision-state expressions are being called and then verify the correct state outcomes.
Normally, one can simply
setCurrentState(someViewState: where you want slot test in within a transitional flow)
define input
mock an ExternalContext
setEvent within that context
resumeFlow(with given context)
verify mocked method calls & finally
assertCurrentState(someViewState: where you would expect to be at, after given input has influenced the decision-state to fork to, within the flow)
It seems decision-states don't operate as a view-state (fair enough: they aren't a given state of view within a flow) so how are we to mock/test?
Thanks in aniticiptation of responses.
Well, I've been put in the right direction by a colleague (the venerable Murray MacPherson) who reminded me that the process is:
1. mock your dao calls
2. begin your flow & (now this is the crux)
3. based on the decision outcomes set by your mocked calls, assert your expected outcome state (which will be some view),
- whether an end state (in which case you would also be expecting an end to your flow) or
- (interim) current state. If it has arrived at exp[ected point, then you know the decisions have been exercised.
N.B. if your expected outcome is a 'currentState', then you can verify the mocked (dao) call/s has/have been made otherwise (as the flow would no longer be active) you cannot make such verifications: the simple fact you've arrived at your expected end state is verification in itself.
In this exact example, you have an alternative to starting at a particular view state via setCurrentState() - you can use startFlow - which will... start the flow. You can then test which view state you end up at, due to the results of your decision states.