Constructor does Real Work

论坛 期权论坛     
选择匿名的用户   2021-5-22 15:42   138   0
<p>http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/ </p>
<p></p>
<h2 style="padding:0px 0px 0.6em; margin:0px 0px 0.75em; font-family:Helvetica,Arial,sans-serif; font-size:2em; color:rgb(86,128,212); background-color:rgb(199,237,204)"> Flaw: Constructor does Real Work</h2>
<div class="entry" style="padding:0px; margin:0px; font-size:1.4em; line-height:1.65em; color:rgb(34,34,34); font-family:Georgia,&#39;Times New Roman&#39;,Times,serif; background-color:rgb(199,237,204)">
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> Work in the constructor such as: creating/initializing collaborators, communicating with other services, and logic to set up its own state <span style="padding:0px; margin:0px">removes seams needed for testing</span>, forcing subclasses/mocks to inherit unwanted behavior.  Too much work in the constructor prevents instantiation or altering collaborators in the test.</p>
<table border="1" cellspacing="0" style="padding:0px; margin:0px; border-collapse:collapse; height:167px; border-width:1px; border-color:rgb(136,136,136)" width="435"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><th style="padding:0px; margin:0px; width:60px">Warning Signs:</th></tr><tr style="padding:0px; margin:0px"><td style="padding:0px; margin:0px">
     <ul style="padding:0px; margin:0px 0px 1.5em 40px; list-style-type:square"><li style="padding:0px; margin:0px 0px 0.5em"><span style="padding:0px; margin:0px; font-family:&#39;courier new&#39;,monospace">new</span> keyword in a constructor or at field declaration</li><li style="padding:0px; margin:0px 0px 0.5em">Static method calls in a constructor or at field declaration</li><li style="padding:0px; margin:0px 0px 0.5em">Anything more than field assignment in constructors</li><li style="padding:0px; margin:0px 0px 0.5em">Object not fully initialized after the constructor finishes (watch out for <span style="padding:0px; margin:0px; font-family:&#39;courier new&#39;,monospace">initialize</span> methods)</li><li style="padding:0px; margin:0px 0px 0.5em">Control flow (conditional or looping logic) in a constructor</li><li style="padding:0px; margin:0px 0px 0.5em">CL does complex object graph construction inside a constructor rather than using a factory or builder</li><li style="padding:0px; margin:0px 0px 0.5em">Adding or using an initialization block</li></ul> </td></tr></tbody></table>
<h3 style="padding:0px; margin:2.5em 0px 0.5em; font-family:Helvetica,Arial,sans-serif; font-size:1em; text-transform:uppercase"> <a name="TOC-Why-this-is-a-Flaw" style="padding:0px; margin:0px; text-decoration:underline" target="_blank"></a>WHY THIS IS A FLAW</h3>
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> When your constructor has to instantiate and initialize its collaborators, the result tends to be an inflexible and prematurely coupled design. Such constructors shut off the ability to inject test collaborators when testing.</p>
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> <span style="padding:0px; margin:0px">It violates the Single Responsibility Principle</span><br style="padding:0px; margin:0px"> When collaborator construction is mixed with initialization, it suggests that there is only one way to configure the class, which closes off reuse opportunities that might otherwise be available. Object graph creation is a full fledged responsibility — a different one from why a class exists in the first place. Doing such work in a constructor violates the Single Responsibility Principle.</p>
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> <span style="padding:0px; margin:0px">Testing Directly is Difficult</span><br style="padding:0px; margin:0px"> Testing such constructors is difficult. To instantiate an object, the constructor must execute. And if that constructor does lots of work, you are forced to do that work when creating the object in tests. If collaborators access external resources (e.g. files, network services, or databases), subtle changes in collaborators may need to be reflected in the constructor, but may be missed due to missing test coverage from tests that weren’t written because the constructor is so difficult to test. We end up in a vicious cycle.</p>
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> <span style="padding:0px; margin:0px">Subclassing and Overriding to Test is Still Flawed</span><br style="padding:0px; margin:0px"> Other times a constructor does little work itself, but delegates to a method that is expected to be overridden in a test subclass. This may work around the problem of difficult construction, but using the “subclass to test” trick is something you only should do as a last resort. Additionally, by subclassing, you will fail to test the method that you override. And that method does lots of work (remember – that’s why it was created in the first place), so it probably should be tested.</p>
<p style="padding-top:0px; padding-bottom:0px; margin-top:0px; margin-bottom:1.5em"> <span style="padding:0px; margin:0px">It Forces Collaborators on You</span></p>
<div style="padding:0px; margin:0px">
  Sometimes when you test an object, you don’t want to actually create all of its collaborators. For instance, you don’t want a real MySqlRepository object that talks to the MySql service. However, if they are directly created using
  <span style="padding:0px; margin:
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP