What is the best practice for writing RSpec tests/examples? Write examples to test the positive/affirmative, the negative, or both?
Fairly new to BDD and RSpec, and I'm really curious as to what people typically do when writing their RSpec tests/examples, specifically as it relates to positive and negative tests of the same thing.
Take for exa开发者_C百科mple validation for a username and the rule that a valid username contains only alphanumeric characters.
The affirmative/positive test would be something like this:
it "should be valid if it contains alphanumeric characters"
username = 'abc123'
username.should be_valid
end
While the negative test would be something like this:
it "should be invalid if it contains non-alphanumeric characters"
username = '%as.12-'
username.should_not be_valid
end
Would you write one test, but not the other? Would you write both? Would you put them together in the same test? I've seen examples where people do any of the above, so I was wondering if there is a best practice and if so, what is it?
Example of writing both positive and negative test:
it "should be invalid if it contains non-alphanumeric characters"
username = '%as.12-'
username.should_not be_valid
username = 'abc123'
username.should be_valid
end
I've seen examples of people doing it this way, but I'm honestly not a fan of this approach. I tend to err on the side of keeping things clean and distinct with a single purpose, much like how we should write methods, so I would be more likely to write two separate tests instead of putting them together in one. So is there a best practice that states something of this sort? That examples should test a single feature/behavior from one angle, not all angles.
In that particular case I would write them both for the positive and negative. This is because you really want to make sure that people with valid usernames are allowed to have them and that people who attempt to have invalid usernames can't do that.
Also this way if a username that should / shouldn't be valid comes through as the opposite to what it should be you'll have those tests already and it's just a simple matter of adding a failing test to the correct category in your tests, confirming that the test does indeed fail, fixing it and then confirming that the test then passes.
So yes, test for both in this case. Not simply one or the other.
I find in any situation like this, it can help to realise that what you're doing isn't really testing. You're providing examples of how / why to use the class and some descriptions of its behavior. If you need more than one example to anchor valuable behavior, I think it's OK to include both.
So, for instance, if I was describing the behavior of a list, I'd have two examples to describe "The list should tell me if it's empty". Neither the empty example nor the full example are valuable on their own.
On the other hand, if you have a default situation in which something is valid, followed by a number of exceptional cases, that "valid" situation is independently valuable. There may be other situations you discover later, for instance:
- should be invalid for non-alphanumerics
- should be invalid for names already taken
- should be invalid for numbers only
- should be valid for accented letters
etc.
In this case, your behavior has two examples by coincidence, rather than because they form two sides of a valuable aspect of behavior. The valid behavior is valuable on its own. So I would have one example per test in this case, but one aspect of behavior per test generally.
This can apply to other, non-boolean behavior too. For instance, if I'm writing ATM software, I would want to both provide cash and debit the account. Neither behavior is valuable without the other.
"One assertion per test" is a great rule of thumb. I find it can be overused, and sometimes there's a case for "one aspect of behavior per test" instead. This isn't one of those cases, but I thought it worth mentioning anyway.
This pattern is usually known as "One Assertion Per Test":
- http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html
精彩评论