Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'd argue that having setup in your tests is an anti-pattern. The setup should be, at most, a single message send to the object under test. Simply call it in your expectation. If you're putting significant code in your test, consider moving that logic to the app.


Quite a bit of the time, you don't want to rely on application logic to do your setup for you. You end up needing the application logic to put things into the DB, without any bugs, in order to be sure your test is actually testing the part of the code it's meant to be testing.

Allowing your application logic to do this for you creates all sorts of opportunity for hard to debug issues that have nothing to do with the thing you were actually testing. Putting data into the test DB directly makes for more setup, but makes for much more isolated test cases and much more certainty that your tests are doing what you think they're doing.

It also means you can write tests as you go without having to build a whole level of application logic to support your single test.


I think a problem with this is that when you bring an actual database into the test, it ceases to be a unit test and becomes an integration test (not that integration tests aren't useful). I would prefer for the application to be separated enough from the database that I can test the business logic entirely on its own.


I would suggest that, aside from at the boundaries of a system, if you find yourself requiring complex setup code then you should evaluate whether your abstractions are neatly decoupled and reduced to minimal necessary complexity.


I disagree. IMHO, modifying your app code for the sake of test code is an anti pattern. It should be viewed as an unfortunate yet necessary, rather than celebrated, action. It taints your design and makes your application harder to understand.


I disagree. If you write tests only after you implement your application and find that they are difficult to test, it is likely not that you are using an anti-pattern in the "unfortunate yet necessary" action of making your code more testable - it is, instead, far more likely, that by failing to write tests as you wrote your implementation, you implemented a poor design that does not decouple abstractions as well as they could be.

It is not a chore to unit test code, it is an extremely useful development tool that forces you to check your assumptions and verify your design as you go to give you a better product.

The attitude of this comment is along the lines of the sorts of attitudes towards testing it takes a lot of effort to un-learn junior engineers of.


Juniors make plenty of mistakes, I would rather they make them then explain why they should change their code rather than them relying on "testable code = better code". I would admit that a junior working alone, or without code review/a mentor, is probably better off relying on that mantra though. Or, perhaps even anyone designing an application significantly larger than they have in the past (without any outside input).

However, everything has a cost, even abstractions. The more powerful the abstraction, the higher the cost. I find that for most of our projects, the sorts of abstractions unit testing forces on us is much more powerful - and thus higher cost - than necessary for the task at hand. If you are not taking advantage of that power, then all you really have left is the high cost.


Nobody even declared code, which is easy to test (verify), as an anti-pattern. Quote, please.


If I have some object I want to test in multiple ways, I find it more convenient to create a single instance during setup and then testing various aspects of just that single instance. Since the constructor of the object in question needs a bunch of values passed in, and each unit test only checks the effects of one at a time, I'm just going to copy and paste a bunch of object initialization code if I don't have a setup step first.


This is not a good practice because a unit test should be able to assume that no other code can possibly modify the data it is using. Later, another engineer could possibly come in with the intent of modifying a single unit test in accordance with an isolated functional change in such a way that the data being used by other unit tests gets modified.

Then some poor fellow ends up redesigning the test suite to actually follow the assumptions of a unit test's test data being only ever accessed by that unit test. I have been that fellow, and it can be, bluntly, quite a pain in the ass; as you're doing it, you can't help but think, "whoever wrote this was too lazy to set up the test data properly, I shouldn't have to spend the time to fix this now."


Ah yes, I should have stated that the object is immutable.


Where are you getting the object to which you're going to send messages?


From the class.

    expect(Klass.new.special_case).to have_this_behavior
Anything more complicated in test code should be considered an anti-pattern.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: