The Model layer should also contain the business logic of your application. Method: A method exists on a class and defines what the class can do. Encapsulation: Ideally, the code for a class should be relatively self-contained through encapsulation, which is the concealment of functional details of a class from the other objects that call its methods. This is typically done by limiting the methods other objects are allowed to call and exposing a public interface through which an object is exposed to the world. In Ruby, this is done with the public, protected, and private keywords.
|Published (Last):||1 April 2016|
|PDF File Size:||9.32 Mb|
|ePub File Size:||7.31 Mb|
|Price:||Free* [*Free Regsitration Required]|
Developers working with other technologies will probably benefit from reading as well. If you think that writing tests is hard — it is, but you just need a little more practice. If you have no one else to talk to about testing in your company, there are many great people to meet at events such as CITCON.
And finally, this is all just advice. If you disagree, feel free to share your thoughts in the comment section below. Now, onwards with the code.
Do not use fixtures. In practice, these shortcomings are addressed by comment essays: RSpec. I recall working on an app where there was a record with dozens of attributes. Whenever a column would be added or changed in the schema, all fixtures needed to be changed by hand. Of course I only recalled this after a few test failures. A common solution is to use factories. If you recall from the common design patterns , factories are responsible for creating whatever you need to create, in this case records.
Factory Bot is a good choice. Factories let you maintain simple definitions in a single place, but manage all data related to the current test in the test itself when you need to. For example: FactoryBot. Factories pulling too many dependencies Factories let you specify associations, which get automatically created. For example, this is how we say that creating a new Comment should automatically create a Post that it belongs to: FactoryBot. But that may not be the case with all associations.
In a large system, calling one factory may silently create many associated records, which accumulates to make the whole test suite slow more on that later. As a guideline, always try to create the smallest amount of data needed to make the test work. Factories that contain unnecessary data A spec is effectively a specification of behavior. That is how we look at it when we open one. Similarly, we look at factories as definitions of data necessary for a model to function.
In the first factory example above, including phone in User factory was not necessary if there is not a validation of presence.
If the data is not critical, just remove it. Factories depending on database records Adding a hard dependency on specific database records in factory definitions leads to build failures in CI environment. This may not be a problem locally because the test database had been created and some kind of seed structure applied some time in the past.
In the CI environment, however, the builds starts from a blank database, so you will have an error before the test suite starts to run. To reproduce and identify such issue locally, you can do db:drop followed by db:setup, and then run your tests again.
Another way is to defer the initialization in a callback. Suppose the following factory definition got commited into your application: FactoryBot. Differently from other specs, these ones have quite a lot of calls to create :category. It turns out that the categories. In other words, an exception will be thrown whenever the same category name gets generated twice during a test.
Factory Bot provides a solution to this problem: sequences. Given that fragile tests are among the worst enemies of a test suite and that you can avoid pulling in an extra dependency such as faker for this very purpose, you might want to avoid using random data in your factories altogether.
Noisy setup This anti-pattern is commonly found in growing and legacy applications. Suppose you are testing a database query that needs to run through a deep object graph.
We are creating a verbose sequence of low-level records that is difficult to comprehend, and its complexity is inherent to the data model and to the query range we need to cover. Since the point of our test is to interact with the database, mocking and stubbing would not help at all. Assuming other examples require inserting more than one bundle of the same structure into the database, copying and pasting the same setup would do nothing but add more noise and thus make matters even worse.
To help understand what we are dealing with, we should first of all lay out the hierarchical structure of the data, which has not been made clear by the above example. The complexity of the data model is nakedly exposed, and we are forced to deal with it every time a similar arrangement is required. We can make our setup look more natural by creating a helper method. The key idea is to not worry about a grand architecture from the beginning and to do the simplest thing possible to improve your spec, and make sure your intent is clearly expressed.
Over time, if you notice other specs repeating a similar arrangement, you can always extract, reuse, and evolve the helper. Want to focus on writing code and not worry about how your tests run?
Rails AntiPatterns: Best Practice Ruby on Rails Refactoring
Rails Antipatterns: Best Practice Ruby on Rails Refactoring