How to test save functions in CakePHP Models? - unit-testing

Just writing some tests for my CakePHP application and I am currently trying to work out the best way to test some functions in my models which end up saving data.
Should I just assertTrue or should I pull the data out of the database and assert the expected result against what is in the database?
There are some values that I have to generate programatically based on the users input so need to be sure they are write. Should I do a find operation within the test and check that the results of that are what I expect?

Use one of the expects to check what you save method returns. I assume you're not talking about save() because that is already tested within the core. So expect in your test whatever your method should return and see if it passes.
And yes, you can do a find within the test to check if your record was saved with the correct values. So find() it and expectEqual() on the result to whatever you expected.
By the way, it's always good to check the core tests to get an idea of how to test certain things or use mock objects. :)

Related

Is there a way to unitary test the arguments passed to Model or Q object?

In my unit tests, I understand how I can mock objects per context, to avoid interacting with any kind of persistent datastore.
I can even mock the Q object to test how many times it has been called, which is really useful.
But I'm still uncomfortable with the fact that while I'm mocking my interaction with the datastores, I'm still assuming that my code works©, that the datastore (or the ORM in this case) is receiving the data correctly, through the "proper channels" so to speak.
Case in point:
# code to test
def related_stuff():
return Stuff.objects.filter(
parent__user__city_name="Las Vegas"
)
# more code...
# testing above
#mock.patch(f"{path_to}.Stuff.objects")
def test_related_stuff(stuff_mock):
stuff_mock.filter.return_value = stuff_mock
stuff_mock.filter.assert_called_once_with(parent__user__city_name="Las Vegas")
How can I actually test that the parent__user__city_name lookup pattern is actually correct and wont result in an error? I'm assuming there's no way to test this without touching the datastore, but any opinions are appreciated.
You could either ensure the database connection(s) are to eg. a memory sqlite instance, or maybe write a Djangon database adapter that straight out errors (or always returns an empty dataset) when a query is attempted.
With an adapter that always returns nothing, you can at least test that a query would work.

Unit Tests: How to Assert? Asserting results returned or that a method was called on a mock?

I am trying to find out the best way to Assert, should I be creating an object with what i should return and check that it has equal to the expected result ?
Or should I be running a method against a mock to ensure that the method was actually called.
I have seen this done both ways, I wondered if anyone has any best practices for this.
Of course, it's quicker and easier to write a unit test to assert that a method was called on the mock but quicker and easier is not always the best way - although sometimes it can be.
What does everyone assert on, that a method has been called or assert the results that were returned ?
Of course its not best practice to do more than 1 assert in a unit test so maybe the answer is to actually assert the results and that the method was called ? So I would create 2 unit tests, 1 to check the results and 1 to check that the method was called.
But now thinking about this, maybe this is going too far, if I get a result that I suppose I can assume that my mock method was called.
In between testing that a method has been called and testing the value that it returns is another possibly more important test: that it was called with the correct parameters.
A very common case these days would a method you're writing that uses some HTTP library to retrieve data from a REST API. You don't want to actually make HTTP requests in your tests so you mock the HTTP client get() method. On the one hand your mock might just return some canned JSON response like (Using RSpec in Ruby as an example):
http_mock.stub(:get).and_return('{result: 5}')
You then test that you can properly parse this and return some correct value based on the response.
You could also test that the HTTP get() method is called, but it's more important to test that it's called with the correct parameters. In the case of an API, your method probably has to format a URL with query parameters and you need to test that it does that correctly. The assertion would look something like (again with RSpec):
http_mock.should_receive(:get).with('http:/example.com/some_endpoint?some_param=x')
This test is really a prerequisite to the previous test, and simply testing that get() was called wouldn't confirm much. For instance, it would tell you if you were incorrectly formatting the URL.

Play framework testing controller method

I have a controller method that fetches data to render(fetched data) a HTML view of the same. I wanted to write a test to ensure the jpa model is queried correctly. However I am not finding a way to intercept what is being passed into render().
Can someone please let me know if there is a way to get what is passed into render from a test case. If not should I move this code/line into a different class that I can test easily.
Thanks
I know it's not exactly what you want but you could just write some selenium tests that will confirm whether the controller is rendering the correct data in the template. (see: http://www.playframework.org/documentation/1.2.4/guide10#selenium)
Also writing a Functional Test may help (see: http://www.playframework.org/documentation/1.2.4/guide10#controller)
Could you see if the Play Response object i.e. the out contains your expected value?

Unit testing style question: should the creation and deletion of data be in the same method?

I am writing unit tests for a PHP class that maintains users in a database. I now want to test if creating a user works, but also if deleting a user works. I see multiple possibilities to do that:
I only write one method that creates a user and deletes it afterwards
I write two methods. The first one creates the user, saves it's ID. The second one deletes that user with the saved ID.
I write two methods. The first one only creates a user. The second method creates a user so that there is one that can afterwards be deleted.
I have read that every test method should be independent of the others, which means the third possibility is the way to go, but that also means every method has to set up its test data by itself (e.g. if you want to test if it's possible to add a user twice).
How would you do it? What is good unit testing style in this case?
Two different things = Two tests.
Test_DeleteUser() could be in a different test fixture as well because it has a different Setup() code of ensuring that a User already exists.
[SetUp]
public void SetUp()
{
CreateUser("Me");
Assert.IsTrue( User.Exists("Me"), "Setup failed!" );
}
[Test]
public void Test_DeleteUser()
{
DeleteUser("Me");
Assert.IsFalse( User.Exists("Me") );
}
This means that if Test_CreateUser() passes and Test_DeleteUser() doesn't - you know that there is a bug in the section of the code that is responsible for deleting users.
Update: Was just giving some thought to Charlie's comments on the dependency issue - by which i mean if Creation is broken, both tests fail even though Delete. The best I could do was to move a guard check so that Setup shows up in the Errors and Failures tab; to distinguish setup failures (In general cases, setup failures should be easy to spot by an entire test-fixture showing Red.)
How you do this codependent on how you utilize Mocks and stubs. I would go for the more granular approach so having 2 different tests.
Test A
CreateUser("testuser");
assertTrue(CheckUserInDatabase("testuser"))
Test B
LoadUserIntoDB("testuser2")
DeleteUser("testuser2")
assertFalse(CheckUserInDatabase("testuser2"))
TearDown
RemoveFromDB("testuser")
RemoveFromDB("testuser2")
CheckUserInDatabase(string user)
...//Access DAL and check item in DB
If you utilize mocks and stubs you don't need to access the DAL until you do your integration testing so won't need as much work done on the asserting and setting up the data
Usually, you should have two methods but reality still wins over text on paper in the following case:
You need a lot of expensive setup code to create the object to test. This is a code smell and should be fixed but sometimes, you really have no choice (think of some code that aggregates data from several places: You really need all those places). In this case, I write mega tests (where a test case can have thousands of lines of code spread over many methods). It creates the database, all tables, fills them with defined data, runs the code step by step, verifies each step.
This should be a rare case. If you need one, you must actively ignore the rule "Tests should be fast". This scenario is so complex that you want to check as many things as possible. I had a case where I would dump the contents of 7 database tables to files and compare them for each of the 15 SQL updates (which gave me 105 files to compare in a single test) plus about a million asserts that would run.
The goal here is to make the test fail in such a way that you notice the source of the problem right away. It's like pouring all the constraints into code and make them fail early so you know which line of app code to check. The main drawback is that these test cases are hell to maintain. Every change of the app code means that you'll have to update many of the 105 "expected data" files.

At what level should I unit test?

Let's say in my user model I have a ChangePassword method. Given an already initialised user model, it takes the new password as a parameter and does the database work to make the magic happen. The front end to this is a web form, where the user enters their current password and their desired new password. The controller then checks to see if the user's current password is correct. If so, it invokes the user model's ChangePassword method. If not, it displays an error to the user.
From what I hear you're supposed to unit test the smallest piece of code possible, but doing that in this case completely ignores the check to make sure the user entered the correct current password. So what should I do?
Should I:
A) Unit test only from the controller, effectively testing the model function too?
OR
B) Create 2 different tests; one for the controller and one for the model?
When in doubt, test both. If you only test the controller and the test fails, you don't know whether the issue is in the controller or the model. If you test both, then you know where the problem lies by looking at the model's test result - if it passes, the controller is at fault, if it fails, then the model is at fault.
A)
The test fails. You have a problem in either the model or the controller, or both and spend time searching through the model and controller.
B)
The model and controller tests fail... chances are you have a problem in the model.
Only the controller test fails... chances are better that the problem is not in the model, only in the controller.
Only the model test fails... hard to see this happening, but if it does somehow then you know the problem is in the model, not in the controller.
It's good to test both layers. It'll make finding the problem later that much easier.
There should be multiple tests here:
Verify the correct password was entered.
Validate the new password, e.g. doesn't match existing one, has minimum length, sufficient complexity, tests for errors thrown, etc.
Updating the database to the new password.
Don't forget that the tests can also help act as documentation of the code in a sense so that it becomes clear for what each part of the code is there.
You might want to consider another option: Mock objects. Using these, you can test the controller without the model, which can result in faster test execution and increased test robustness (if the model fails, you know that the controller still works). Now you have two proper unit tests (both testing only a single piece of code each), and you can still add an integration test if required.
Unit testing means to test every unit on its own, so in this case you would need to build two unit tests, one for the frontend and one for the backend.
To test the combination of both an integration test is needed, at least the ITSQB calls it like that.
If you code object oriented you usually build unit tests for every class as that is the smallest independent unit testable.
A) is not a unit test in my opinion since it uses more than one class (or layer). So you should really be unit-testing the model only.