Patch a class method used in a view - django

I'm trying to test my view given certain responses from AWS. To do this I want to patch a class I wrote to return certain things while running tests.
#patch.object(CognitoInterface, "get_user_tokens", return_value=mocked_get_user_tokens_return)
class TestLogin(TestCase):
def test_login(self, mocked_get_user_tokens):
print(CognitoInterface().get_user_tokens("blah", "blah")) # Works, it prints the patched return value
login_data = {"email": "whatever#example.com", "password": "password"}
response = self.client.post(reverse("my_app:login"), data=login_data)
Inside the view from "my_app:login", I call...
CognitoInterface().get_user_tokens(email, password)
But this time, it uses the real method. I want it to use the patched return here as well.
It seems my patch only applies inside the test file. How can I make my patch apply to all code during the test?
Edit: Never figured out why #patch.object wasn't working. I just used #patch("path.to.file.from.project.root.ClassName.method_to_patch").
Also, see: http://bhfsteve.blogspot.com/2012/06/patching-tip-using-mocks-in-python-unit.html

Most likely CognitoInterface is imported in the views.py earlier than the monkeypatching happens. You can check this by adding print() into the views where CognitoInterface is imported (or declared, it's not obvious from the amount of code here), and then another print() next to the monkeypatching.
If the monkeypatching happens latter, you have to either delay the import, or in worst case monkeypatch in both places.

Related

How to unit test a method not invoking another object method in RSpec

I have a rails controller which I would like to test a method test_method.
class ActiveController < ActionController::Base
def test_method
user = acc_users.all_users.find params[:id]
if !user.active?
user.call_method!
end
end
end
I have to test that call_method isn't being called. This is what I have come up with but I don't think this will work.
it "should not call call_method" do
u = user(#acc)
put :test_method, :id => u.id
expect(u).not_to have_received(:call_method!)
end
I followed this question here and found it almost similar except that the method being called is in another class. When I try this above code I get an error message like "expected Object to respond to has_received?"
I believe I will not be able to test this with the given setup as the user is not being injected in the test_method.
call_method is a call to a method that enqueues a job so I want to be sure it doesn't get invoked.
How would I go about testing this method?
You could use the expect_any_instance_of method on User model with a count, say "n", to test that the model receives a particular method "n" times.
Also, you would have to set this expectation BEFORE actually calling your action because the expectation is based on something that happens inside the action itself, and not on something that the action returns.
The following line should work, assuming your user variable is an instance of the class User:
u = user(#acc)
expect_any_instance_of(User).to receive(:call_method!).once
put :test_method, :id => u.id
Alternately, you could change the spec to behave like a black box, rather than test invocations of particular methods. For example, you could mock call_method! to always return a value such as and then continue your test based on that if that is possible. That could be achieved using expect_any_instance_of(User).to receive(:call_method!).and_return(<some_object>). Your test could later be assumed to behave according to the value of that you have set. This alternate solution is just a suggestion, and it is likely that it may not work according to your specific needs.

How do I unit test RxJava Completable doOnSuccess function?

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

Passing parameters to tearDown method

Suppose I have entity that creates SVN branch during its work. To perform functional testing I create multiple almost same methods (I use python unittest framework but question relates to any test framework):
class Tester(unittest.TestCase):
def test_valid1_url(self):
url="valid1"
BranchCreator().create_branch(url)
self.assertUrlExists(url) # assume I have this method implemented
def test_valid2_url(self):
url="valid2"
BranchCreator().create_branch(url)
self.assertUrlExists(url) # assume I have this method implemented
def test_invalid_url(self):
url="invalid"
self.assertRaises(ValueError, BranchCreator().create_branch, url)
After each test I want to remove the resulting branch or do nothing if test failed. Ideally I would use something like following:
#teardown_params(url='valid1')
def test_valid1_url(self):
def tearDown(self, url):
if (url_exists(url)): remove_branch(url)
But tearDown does not accept any parameter.
I see few quite dirty solutions:
a) create field "used_url" in Tester, set it in every method and use in tearDown:
def test_valid1_url(self):
self.used_url="valid1"
BranchCreator().create_branch(self.used_url)
self.assertUrlExists(url)
...
def tearDown(self):
if (url_exists(self.used_url)): remove_branch(self.used_url)
It should work because (at least in my environment) all tests are run sequentally so there would be no conflicts. But this solution violates tests independency principle due to shared variable, and if I would manage to launch tests simultaneously, it will not work.
b) Use separate method like cleanup(self, url) and call it from every method
Is there any other approach?
I think that the b) solution could work even if it mandates to have the call to the helper method in every test and that sounds to me like a sort of duplication.
Another approach could be the calling the helper method inside the "assertUrlExists" function. In this way the duplication is removed and you can avoid to check again the existence of the URL in order to manage the cleanup: you have the assertion result and you can use it.

Spock Testing when method under test contains closure

I'm using grails plugin multi-tenant-single-db. Within that context I need to write a spock test in which we temporarily remove the tenant restrictions. Location is my Tenant, so my method looks like this:
def loadOjectDetails(){
Location.withoutTenantRestriction{
// code here to retrieve specific items to the object to be loaded
render( template: "_loadDetails", model:[ ... ]
}
}
The method runs as expected, but trying to put method under test coverage the error output suggests that:
groovy.lang.MissingMethodException: No signature of method: com.myPackage.myController.Location.withoutTenantRestriction() is applicable for argument types:
and a stacktrace that stems on from there.
Do I need to Stub this? The withoutTenantRestriction is a wrapper around my entire method logic.
UPDATE:
The test code looks like this:
given:
params.id = 3002
currentUser = Mock(User)
criteriaSetup()
controller.getSalesOrder >> salesOrders[2]
when:
controller.loadOrderManageDetails()
then:
(1.._) controller.springSecurityService.getCurrentUser() >> currentUser
expect:
view == 'orderMange/orderManageDetail'
model.orderInstance == salesOrders[2]
Yes! You should be stubbing it as is created at run time not compile time.
You could stub it like below:
Your_Domain.metaClass.withoutTenantRestriction{Closure closure ->
closure.call()
}
This way your regular code will work in test cases. Also,as in withoutTenantRestriction it basically starts a new hibernate session, which doesn't matter much as now you have stubbed the closure, you could perform desired action in place of calling closure.call() only.
Also, same could be applied to withThisTenant.
In integration tests you don't need to stub it as is loading the whole environment.
Hope it helps!!

Unit test a Flask session - cannot reproduce failure with session_transaction

I am testing a Flask application (Flask 0.9), and in particular I have a session fixture that I would like to run in the documented-way, being something like this (as I understand it):
from flask import Flask, session
app = Flask(__name__)
#app.route('/', methods=['POST'])
def m():
logging.error(session) # expect {'x': 1}
return ""
with app.test_request_context() as trc:
with app.test_client() as c:
with c.session_transaction() as sess:
sess['x'] = 1
c.post()
This works as expected, with the output being something like this:
ERROR:root:<SecureCookieSession {'x': 1}>
Unfortunately I am encountering an unexpected result where the session data is not set in the endpoint function, i.e. the output is something like this:
ERROR:root:<SecureCookieSession {}>
This issue exhibits only when run from my unit testing framework. As it stands, I am unable to reproduce this problem with a degenerate case, though I have made a fairly substantial effort with a gist of some of this effort here. The salient points being that I have included itsdangerous and Google App Engine testbed, expecting maybe one of them to have been the cause.
On my own system I have gone further than the gist, and almost completely replicated my unit test framework trying to isolate this. Likewise, I have removed ever-increasing amounts of relevant code from my testing framework. To the point, I am unable to think of differences between the degenerate case and my stripped-down framework that could influence the outcome. I have traversed the c.post() call in pdb to try eek out the cause of this malignity, but have yet to glean any useful insight.
Which is all to say, I would be grateful for a little direction or suggestion as to where the issue may lie. What could possibly be influencing the Werkzeug context in such a way that the session_transaction is not being honoured?
In my case, I was restricting cookies to a specific domain automatically by loading a configuration file. By updating the configuration on-the-fly, I was able to get cookies to work while unit testing. Setting the SESSION_COOKIE_DOMAIN property to None, all domains (namely localhost) were able to set sessions.
app.config.update(
SESSION_COOKIE_DOMAIN = None
)
You may want to fiddle around with the configuration settings described under Configuration Handling in the docs.
I hate to resurrect an old question, but I believe that I figured out the solution to this issue. For testing, try setting your server name to localhost:
app.config['SERVER_NAME'] = 'localhost'
I was originally using Brian's hack, but this solved the problem for me.
Without a testcase that actually fails it's hard to say much anything. All I can think of is that the TestClient instance you're using the make the request is different from the one you use to set up the session. E.g. you could make the gist fail as expected with this:
with self.app.test_client() as c:
with c.session_transaction() as sess:
sess['d'] = 1
self.client.post()
But as this isn't the case here or the gist, go figure.
Here is what I ended up doing:
# Code that modifies the current `session`; we must be in a test context already.
headers = {}
with self.client.session_transaction():
# Get the cookie that is sent to the browser to establish a connection
# via a fake request.
response = make_response()
self.app.session_interface.save_session(self.app, session, response)
headers['Cookie'] = response.headers.get('Set-Cookie', '')
self.client.post(..., headers=headers) # also works for .get, .put, etc.