Posts for category: ask a tester
Questions: Where To Test Sessions And Roles
Questions, I get questions. Well, sometimes I do. Here’s one. And sorry, this should have been posted here a couple of weeks ago.
[In my project] Only admin users are allowed to add users or inactivate them which means among other things that the user must be an admin and logged in.I struggled for a while with trying to make a unit test work with this and had issues with the fact that there’s no active session while running unit tests. That further revealed that having this logic in the model is problematic too. People posted ways to make this work, but it appears to be frowned upon. Eventually, I just removed this from the model and placed it in the controller and correspondingly moved the test to the users_controller_test.rb.
So, the correct place for this test is the functional test for users from a testing/functionality philosophical standpoint?
Short answer:
I agree with your conclusion. Logic having to do with authentication and access should be tested in the controller test.
Longer answer:
As you correctly note, sessions are not available in the model test environment, which in my experience is a hint and a half from the Rails core team that they really don’t want you doing that. Rails core is never particularly shy about denying or limiting access to things they don’t want you to be able to do easily. That said, it’s not that hard to fake, see the section in the book for testing helpers for an example of how to get session features in a unit test environment.
From a philosophical standpoint, you want to split the access from what is actually the logic in the model. In other words, whether you need to be a logged in admin to get to the add users page is properly a controller test, so is the idea that if you check this box, the the user’s active status changes. However, if changing the users active status triggers other logic in the model, like some kind of activity history or some such, then there should be a model method with a name like “inactivate” and that method should be tested in the model tests.
Ask A Tester Person: Writing Multiple Tests at Once
It’s time for another episode of Ask A Tester Person…
This is from Jônatas Paganini, writing from Brazil—I’ve paraphrased his question slightly, I hope I’m preserving the original intent.
In response to my advice on Page 11 of Getting Started about not writing too much code without tests, Jônatas asks about the opposite process.
What do you think about write a lot of tests before implementing the code? When running those tests, some of them break and I need to start fixing those tests. Is this a bad practice? I think that when I write just one test at a time I lose focus more easily.
Great question. I have several overlapping responses to this that I hope I can make coherent.
First off, as much as I love talking about theory in software development, practicality is obviously more important. If something works for you, then it works, and you don’t necessarily need to justify it. (That said, it’s always valuable to try new things to find out if there’s another way that works even better…)
As for this specific practice of writing multiple tests before writing code, my basic response is that I’ve generally regretted it the times that I’ve tried it, but that there are cases where it’s appropriate. It’s a much better practice to write a lot of tests first than it is to write a lot of code first.
The problems that I have with writing a bunch of tests up front are kind of subtle, and generally only an issue if you are writing, say, five or test tests in a row. Writing a couple of tests consecutively is usually not a problem, especially if the two tests are related enough to be covered by the same code.
The first problem is that writing all the tests up front tends to take away from the discovery part of the test-first process. Often, especially when writing code that’s not perfectly specified, writing a batch of code will suggest the next test, because there’s a clear weakness in the code that the next test will expose. This process will often lead to cleaner code at the end, I think, because of the way it gets built up in small steps. Writing all the tests at once makes it harder (but not impossible) to have the design emerge in the same way. For that reason, writing multiple tests at once is probably best done when dealing with a well-understood and specified algorithm.
Another way of describing this is to say that the more tests you write, the more the tests need to assume about the structure of code not yet written. You want to be careful that this doesn’t limit the final code. I will often wind up a test-first process with a more elegant solution than I would have imagined at the beginning. I think that going in one test at a time makes that easier.
The bigger problem, at least for me, is that if I write five tests in a row, I’d expect them all to fail. I find it hard to focus on multiple test failures at a time—if I do a refactor that breaks tests, I will often temporarily comment out tests so that I can deal with the broken tests one by one. Again, there are circumstances where this doesn’t apply. Sometimes, you’ll be writing error case tests that you are pretty sure that the code will handle. In that case, there’s less of a problem with writing multiple tests at once.
I do think the RSpec functionality of allowing you to specify the names of future tests without implementing them is often valuable as a partial version of this practice. By doing this you remember any error or unusual cases that you need to test, and you don’t get constrained by having to implement the tests against code that doesn’t yet exist.
More About Factories
This would be a great time to mention that if you have an questions to ask about Rails testing, put them in the comments or email them to railsprescriptions at gmail dot com and I’ll try to address them here.
First up: Felipe Coury, from the comments:
Would you mind on elaborating on the factory approach versus traditional approach of using fixtures, either on a new article or even replying to this comment with references you may have?
Sure—this will be covered in some detail in the book itself, but it’s also worth some attention here.
The goal of the factory approach is to work around two of the weaknesses of fixtures: brittleness and opacity. These problems generally show up when you try to use fixtures for something that requires a lot of data, like search or report functionality. The workflow pattern often is to create a bunch of fixtures, then write tests that validate that, say, searching for “Smith”, returns the correct two records.
The first problem comes when somebody needs to add a new record to the fixture set to expose a different case for a different test, but the new global set of fixtures breaks existing reporting tests. Eventually this becomes a real pain. Also, when you read the test that says that searching for Smith returns two records, you need to back up and check out the fixture file to verify that. In my experience, that leads to a lot of tests where you write the test, and just fill in the value that the program spits out, rather than determining the results before writing the test.
The alternate approach is to create separate data for each individual test. The goal of the various factory tools (Factory Girl, Fixture Replacement, and Machinist are three to look at) is to make creating data for each test easy enough to make it a viable option for complicated testing.
All three of these tools are similar enough for my purposes here—essentially you have a file where you define default templates for each ActiveRecord model in your system plus a factory method that creates a new instance based on the default values. The default values can be dynamic (Faker works nicely here to create random structured data), and you can override any value in the template with the actual value you need for the test.
The goal here is to get new objects with a minimum of typing and, more importantly, with the key values needed for the test highlighted and the values that are irrelevant to the test in the background. This can make the test much easier to read. The pattern is to create a minimum amount of data for each test, focused on exposing the specific issue under test. Here’s an example, using Machinist syntax.
test "I have two doggies" do
@doggie = Dog.make(:name => "Mr. Puddles")
@other_doggie = Dog.make(:name => "Rex")
assert_equal(2, Dog.all.size)
end
The advantage is that you can create exactly the data you need for each test easily enough that it doesn’t seem like a burden. Each test is independent, and easy to read. If you do wind up needing the same setup in multiple tests, it’s easy enough to move the calls to a common method, or use one of the various context tools.
context "with two doggies" do
setup do
@doggie = Dog.make(:name => "Mr. Puddles")
@other_doggie = Dog.make(:name => "Rex")
end
test "the doggies can be friends"
@doggie.befriend(@other_doggie)
end
end
There are two downsides that I have encountered. One is speed—fixtures by default use database transactions to optimize loading, factories generally don’t. This can slow things down, but if you are using the factories to create only the minimum amount of data for each test, you should still be okay. Similarly, it’s easy for the factory setup data to get so complex that it winds up in it’s own method, then it’s own module, which can take you close to the hard-to-read nature of fixture tests. I still think the factory tests are better, because you can group data from different models in the same file, but it’s something to watch out for.
Hope that helps, let me know if there are other questions you want me to cover here.


