tag:blogger.com,1999:blog-15045980.post3023874871164884317..comments2024-03-18T02:13:03.999-07:00Comments on Google Testing Blog: Writing Testable CodeMarkohttp://www.blogger.com/profile/16755629501705100354noreply@blogger.comBlogger32125tag:blogger.com,1999:blog-15045980.post-6867501680963025242018-10-31T07:17:48.969-07:002018-10-31T07:17:48.969-07:00Fixed! Thanks!Fixed! Thanks!Google Testing Bloggershttps://www.blogger.com/profile/03153388556673050910noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-29635835235821084652018-10-09T17:19:57.779-07:002018-10-09T17:19:57.779-07:00Thanks for the article. Awesome tips!
While re...Thanks for the article. Awesome tips! <br /><br />While reading through it, I found some things that sound like typos or minor grammatical errors? I'll post them here, in case you have time/interest to fix them. :) I'll post them into the copy on your blog too.<br /><br /><br />Thanks!<br />Matt<br /><br />___<br />- "OK, you got rid of your new operators in you application code." -> <br />"OK, you got rid of your new operators in your application code." <br /><br />- "Global state is bad from theoretical, maintainability, and understandability point of view," -> <br />"Global state is bad from theoretical, maintainability, and understandability points of view,"<br /><br />- "The core of the issue is that the global instance variables have transitive property!" -> <br />"The core of the issue is that the global instance variables have a transitive property!"<br /><br />- "Seams are needed so that you can isolate the unit of test." -> <br />"Seams are needed so that you can isolate the unit test."<br /><br />- "If you build an application with nothing but static methods you have procedural application." -> <br />"If you build an application with nothing but static methods you have a procedural application."<br /><br />- "I don't know how to test application without seams." -> <br />"I don't know how to test an application without seams."<br /><br />- "How much a static method will hurt from a testing point of view depends on where it is in you application call graph." -> <br />"How much a static method will hurt from a testing point of view depends on where it is in your application call graph."<br /><br />- "At run-time you can not chose a different inheritance, but you can chose a different composition, this is important for tests as we want to test thing in isolation." -><br />"At run-time you can not choose a different inheritance, but you can choose a different composition, this is important for tests as we want to test a thing in isolation."<br /><br />- "This will clutter the focus of test" -><br />"This will clutter the focus of the test"<br /><br />- "This helps testing since simpler/smaller class is easier to test." -> <br />"This helps testing since a simpler/smaller class is easier to test."<br /><br />- "If summing up what the class does includes the word "and", or class would be challenging for new team members to read and quickly "get it", or class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns." -><br />"If summing up what the class does includes the word "and", or the class would be challenging for new team members to read and quickly "get it", or the class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns."<br /><br />- "These classes are hard to tests since there are multiple objects hiding inside of them and as a resulting you are testing all of the objects at once." -><br />"These classes are hard to tests since there are multiple objects hiding inside of them and as a result, you are testing all of the objects at once."<br />___<br /><br />MPursleyhttps://www.blogger.com/profile/06760459303233369064noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-32552184409221530432016-10-22T12:31:44.004-07:002016-10-22T12:31:44.004-07:00RDM vs. ADM
--------------------------------------...RDM vs. ADM<br />----------------------------------------------------------------<br /><br />If you separate logic from data in an Object Oriented language, you actually fall back to procedural programming. (A.K.A, by Fowler, "ADM")<br /><br />Many companies do that for the sake of testing.<br /><br />However, if you still want to write real Object Oriented and benefit a rich domain model:<br /><br />1. Separate your project to modules.<br />2. Each module will have a thin service layer made of stateless logic.<br />3. Use "new" to instantiate business objects.<br />4. Use service locator or IoC container to resolve services provided by other modules.<br /><br />Anonymoushttps://www.blogger.com/profile/09955936466667484870noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-82464410070635126092014-10-08T18:20:53.186-07:002014-10-08T18:20:53.186-07:00Continuing on the OOP bias point (Mike December 2,...Continuing on the OOP bias point (Mike December 2, 2011).<br />FP is becoming more and more popular and OO languages allow for more and more of a FP/OOP mix.<br /><br />If you think about this list in therms of FP, all points are N/A!<br /><br />In this context, I would like to suggest a shorter list to produce a much more testable code:<br />1) limit side-effects<br />2) isolate side-effects<br /><br />Also, in the context of FP, I very much disagree with point 6. The term 'method' is somewhat redeeming but... <br />A true FP language like Haskell will have a very 'static' feel to it. In OOP/FP hybrid if you want to code with functions instead of methods these functions will need to have static presence too. For example: if 'reduce' is a function that accept an accumulator and a list (instead of being a method owned by the list), it has to exist outside of the list object. I took the approach of using lots of static definitions when designing fpiglet (FP library for Groovy) and I believe it to be some of the most testable code I ever done within the boundaries of an OO language. <br />Robert Peszekhttps://www.blogger.com/profile/05661893962783045407noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-90846027186190697332013-08-21T07:57:40.135-07:002013-08-21T07:57:40.135-07:00I guess "branches" would be the correct ...I guess "branches" would be the correct term as opposed to "seams".Anonymoushttps://www.blogger.com/profile/01254501614552987859noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-53718372314938330012012-12-29T13:42:45.245-08:002012-12-29T13:42:45.245-08:00How does one deal with dynamically created objects...How does one deal with dynamically created objects (say) like objects representing email?Misrajihttps://www.blogger.com/profile/09038509808820139393noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-75761844698305622202012-12-28T20:00:07.810-08:002012-12-28T20:00:07.810-08:00@Florin:
I do follow your argument about not organ...@Florin:<br />I do follow your argument about not organizing code into value object and service objects for simulation software.<br /><br />But my theoretical understand of OO is that an object is Procedural abstraction of Data. That is data being represented purely by its behavior. <br />Service Objects perfectly fit the definition. What is being hidden, is their own state, which should be nobody's concern.<br /><br />OTH, not all data can be represented by behavior only. In such cases, having a value object makes sense.<br /><br />Thus IMHO, the advice about dividing the code into Value Objects and Service Objects still seems reasonable.<br /><br />Is my reasoning incorrect?Misrajihttps://www.blogger.com/profile/09038509808820139393noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-78146416290822244852012-09-14T00:27:14.443-07:002012-09-14T00:27:14.443-07:00Organizing your code into value objects and servic...Organizing your code into value objects and services is highly non-OO, and was named by (IIRC) Fowler the anemic domain model. I have used it successfully in several LOB apps, but it is specifically damaging when the interactions between your domain-specific objects are rich and complex (like for example in a physical simulation of a system if interacting particles). In such cases, organizing your code into value objects and services rightout harms testability. Therefore I wouldn't include this advice in the list.<br />Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-15045980.post-80941956633022966302012-09-14T00:04:02.275-07:002012-09-14T00:04:02.275-07:00Build yourself a test fixture using an in-mem data...Build yourself a test fixture using an in-mem database, and add database initialization code to the test fixture class. Sure, it's some overhead, but if you do it right, you only do it once for all DAO tests you write in an application - and IME there are many of them.<br />Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-15045980.post-70325795926772445222012-07-20T05:25:52.532-07:002012-07-20T05:25:52.532-07:00Do you test the code that creates the object graph...Do you test the code that creates the object graph? If so, how?Anonymoushttps://www.blogger.com/profile/16349528857903348489noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-19289680810818277772011-12-02T16:03:30.167-08:002011-12-02T16:03:30.167-08:00Good article, most points I agree with. However, t...Good article, most points I agree with. However, there is a strong Java/C# bias in your explanations (or pure OOP bias), and it might be good to stress that fact as some points don't apply as strongly to other languages. Also, this statement made be jump out of my chair:<br /><br />"Polymorphism: at compile-time the method you are calling can not be determined"<br /><br />You need to review your basic software engineering knowledge. The definition you give pertains to "dynamic binding", not polymorphism. Polymorphism is essentially the concept of substitutability of types. In other words, being able to substitute one object-type for another and be able to reuse the same method that uses either types is the key aspect of polymorphism (i.e. the object types are polymorphic types and the functions using them are polymorphic functions). This does NOT require dynamic binding, it is only if you need to make this substitution at run-time that dynamic binding is required. Haven't you heard of something called "static polymorphism" (i.e. polymorphism that is realized at compile-time). This also exemplifies my point about the strong OOP bias in your article. I write an enormous amount of procedural code (in C++), heavily relying on static polymorphism, and thus, has a lot of "seams" making the construction of unit-tests very easy (and generally sticking to state-less functional programming is also a huge benefit in that regard). Certainly, in OOP, good use of dynamic polymorphism will make unit-testing a lot easier, but this does not mean that procedural programming (that doesn't use dynamic polymorphism) is hard to unit-test, it's just hard to do so if you suck at writing procedural code.<br /><br />So overall, I would say that point 6 should be taken out (or left with a strong caveat that this applies only to highly restrictive programming languages that don't allow you to achieve static polymorphism). Then, points 4 and 5 are the same (do you really think anyone who knows what a Singleton is doesn't know that it's forms a global state). Point 3 only applies to languages with reference-semantics with non-deterministic construction models (Java/C# and the like), in a language like C++, this point is mute (unless you are emulating Java/C# style OOP in C++, which is just a very bad style of C++). The remaining points are good IMO.<br /><br />Just my grain of salt.Mikehttps://www.blogger.com/profile/09562341153779790523noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-13294491030758040412011-05-21T03:05:41.622-07:002011-05-21T03:05:41.622-07:00Great article. I tried for one hour+ to make this ...Great article. I tried for one hour+ to make this point to a colleage y-day. I'll just send her this article.Kalle Karlberghttps://www.blogger.com/profile/01261594292417162687noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-21323256253659761072010-05-14T05:03:31.473-07:002010-05-14T05:03:31.473-07:00it's good to see this information in your post...it's good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.jenniferhttps://www.blogger.com/profile/09226241977752348399noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-33105471797190002142010-03-22T07:34:35.176-07:002010-03-22T07:34:35.176-07:00If I could wrap my head around it, I"ll try :...If I could wrap my head around it, I"ll try :).Geshan Manandharhttps://www.blogger.com/profile/07031000783575075307noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-49488395205374858072009-09-02T23:38:22.003-07:002009-09-02T23:38:22.003-07:00Excellent topic and content. Keep them comingExcellent topic and content. Keep them comingEdward Huynhhttps://www.blogger.com/profile/00418812029212591688noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-56677424628951273662009-06-28T06:23:55.523-07:002009-06-28T06:23:55.523-07:00About Singletons, I completely agree. I posted thi...About Singletons, I completely agree. I posted this article on my blog: http://prettyprint.me/2009/06/24/beware-of-the-singleton/Ran Tavoryhttps://www.blogger.com/profile/08860493178316395693noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-62910017422878338092008-08-26T16:38:00.000-07:002008-08-26T16:38:00.000-07:00If you have a spring project and you want to test ...If you have a spring project and you want to test a dao - how do you do that *easily*.<BR/><BR/>Everyone just says, "use dbunit".<BR/><BR/>But I don't see how that makes it easy.Unknownhttps://www.blogger.com/profile/06521462820517167511noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-9361414418264279752008-08-08T12:23:00.000-07:002008-08-08T12:23:00.000-07:00This is an interesting article, but the list is ra...This is an interesting article, but the list is rather confusing. Some of the titles are things that you SHOULD do, and some are things that you should NOT do. It is only when you read the body of the list that it becomes clear (and sometimes even then it is not always obvious). I suggest prepending each list item with DO or DONT to make it clear, or rewriting them to make them consistent. <BR/><BR/>To be specific, all of the points are things you should NOT do, except for 2, 7 and 8, which you SHOULD do.Dave Kirbyhttps://www.blogger.com/profile/05692608289845036146noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-27347019480932067182008-08-08T12:11:00.000-07:002008-08-08T12:11:00.000-07:00@Imran and @Michel:Thanks! This seems like someth...@Imran and @Michel:<BR/><BR/>Thanks! This seems like something I've done for a while without knowing what it was called. I appreciate the explanation!Max Cantorhttps://www.blogger.com/profile/00162681176688582120noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-76542966928056246382008-08-07T16:27:00.000-07:002008-08-07T16:27:00.000-07:00interesting articleinteresting articleihathhttps://www.blogger.com/profile/02627703958246416901noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-74137266151723779012008-08-07T14:01:00.000-07:002008-08-07T14:01:00.000-07:00groby:asking:There are two ways. None of them use ...groby:<BR/><BR/>asking:<BR/><BR/>There are two ways. None of them use a ServiceLocator.<BR/><BR/>1) receiving what you need directly in the constructor/setter. I mean: if you need something let your client code give it to you.<BR/><BR/>new Car(FuelTank)<BR/><BR/>2) receiving a Provider (NOT A SERVICELOCATOR).<BR/>It's a subttle diferrence:<BR/><BR/>A ServiceLocator is bad because it's a general/global entry-point. It's application-aware, not component-aware. So your code becomes less independent.<BR/><BR/>A Provider (as I propose it) is an interface defined by the very class you are writing and who implements it ONLY does that.<BR/><BR/>example:<BR/><BR/>new Engine(FuelProvider)<BR/><BR/>as I cannot give fuel to the engine directly on the constructor (it's going to ask for it when it runs) I have to give it when the class wants. So that class (Engine) defines the interface FuelProvider:<BR/><BR/>examples.car.engine.Engine<BR/>examples.car.engine.FuelProvider<BR/><BR/>and somebody implement it how he/she wants:<BR/><BR/>examples.car.NormalFuelProvider implements<BR/>examples.car.engine.FuelProvider<BR/>{<BR/> // uses FuelTank<BR/>}<BR/><BR/>NormalFuelProvider is more application-dependant that FuelProvider interface. It's fine because it's created for wiring things in an application (assume car is the application). At least, in the example is something that's made for creating a car with an Eingne and a FuelTank.<BR/><BR/>Getting back to the ServiceLocator what I mean is you can implement a Provider that's aware of the ServiceLocator but your class Engine not.<BR/><BR/>If you want to test it you can give an AllTheFuelYouWantProvider that do mock-like stuff so you can concentrate on the Engine. You don't have to worry about any ServiceLocator (or FuelTank), don't have to worry about application-like code, and your tests are happier.helioshttps://www.blogger.com/profile/05332622210307703410noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-66262630505997922362008-08-07T13:50:00.000-07:002008-08-07T13:50:00.000-07:00More about polymorphism:maybe examples on how to u...More about polymorphism:<BR/><BR/>maybe examples on how to use polymorphism can be found in the strategy pattern (Gamma 1994). It happens a lot of time (the most when your building some kind of tool/framework) you need to do a generic work (loading database field values into an object, by example), but this generic thing has it's specialties (converting types, converting special values, getting the value, etc). That's when you delegate that special thing (converter.getValueFromBD(...)) and use polymorphism to implement it in various ways (IntegerConverter, ClobToStringConverter, StringConverter, etc, etc, etc).<BR/><BR/>By the way: strategy is a pattern like template-method except that it preffers composition [using a strategy] than inheritance [overriding the template method]. It illustrate the point about composition vs. inheritance.helioshttps://www.blogger.com/profile/05332622210307703410noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-82828902059654592008-08-07T13:45:00.000-07:002008-08-07T13:45:00.000-07:00Hm. You have me stumped with the "ask, don't look ...Hm. You have me stumped with the "ask, don't look for" advice. <BR/><BR/>Who exactly would I be asking for the objects I need if I *don't* pass in a ServiceLocator? A global service locator instead?Grobyhttps://www.blogger.com/profile/17545002324094677432noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-80713025726963991732008-08-07T13:38:00.000-07:002008-08-07T13:38:00.000-07:00@Max,Let's say you are developing a chat service t...@Max,<BR/><BR/>Let's say you are developing a chat service that combines various chat protocols, and you want to implement logout() functionality.<BR/><BR/>Switch version:<BR/><A HREF="http://pastebin.com/f23bf0c6e" REL="nofollow">http://pastebin.com/f23bf0c6e</A><BR/><BR/>Polymorphic version:<BR/><A HREF="http://pastebin.com/fae7a445" REL="nofollow">http://pastebin.com/fae7a445</A><BR/><BR/>Admittedly, the above example is not the most apt but it is based of a real world refactoring I did a while ago. If you want a more typical example, try <A HREF="http://hanuska.blogspot.com/2006/08/swich-statement-code-smell-and.html" REL="nofollow">http://hanuska.blogspot.com/2006/08/swich-statement-code-smell-and.html</A><BR/><BR/>Regards,<BR/>Imran FanaswalaImran Fanaswalahttps://www.blogger.com/profile/00924554194586998000noreply@blogger.comtag:blogger.com,1999:blog-15045980.post-53107193265550674412008-08-07T13:07:00.000-07:002008-08-07T13:07:00.000-07:00Max "Could you perhaps give a little code snippet ...Max "Could you perhaps give a little code snippet that exemplifies this?"<BR/><BR/>Assume you have a class named "Message" with a method named "sendMessage()" that contains this fragment :<BR/><BR/>if (this.messageType = messageTypes.Fax) {<BR/> ...<BR/>}<BR/><BR/>then you should probably have a FaxMessage class that inherits from Message and overrides sendMessage().Unknownhttps://www.blogger.com/profile/12599839777596474701noreply@blogger.com