Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I keep reading about people who are "test infected", meaning that they don't just "get" TDD but also can't live without it. They've "had the makeover" as it were. The question is, how do I get like that?
Part of the point of being "test infected" is that you've used TDD enough and seen the successes enough that you don't want to code without it. Once you've gone through a cycle of writing tests first, then coding and refactoring and seeing your bug counts go down and your code get better as a result, not only does it become second nature like Zxaos said, you have a hard time going back to Code First. This is being test infected.
You've already read about TDD; reading more isn't going to excite you.
Instead, you need a genuine personal success story.
Here's how. Grab some code from a core module, code that doesn't depend on external systems or too many other subroutines. Doesn't matter how complex or simple the routine is.
Then start writing unit tests against it. (I'm assuming you have an xUnit or similar for your language.) Be really obnoxious with the tests -- test every boundary case, test max-int and min-int, test null's, test strings and lists with millions of elements, test strings with Korean and control characters and right-to-left Arabic and quotes and backslashes and periods and other things that tend to break things if not escaped.
What you'll find is.... bugs! At first you might think these bugs aren't important -- you haven't run into these problems yet, your code probably would never do this, etc. etc.. But my experience is if you keep pushing forward you'll be amazed at the number of little problems. Eventually it becomes hard to believe that none of these bugs will ever cause a problem.
Plus you get a great feeling of accomplishment with something is done really, really well. We know code is never perfect and rarely free of bugs, so it's nice when we've exhausted so many tests that we really do feel confident. Confidence is a nice feeling.
Finally, I think the last event that will trigger the love will happen weeks or months later. Maybe you're fixing a bug or adding a feature or refactoring some code, and something you do will break a unit test. "Huh?" you'll say, not understanding why the new change was even relevant to the broken test. Then you'll find it, and find enlightenment. Because you really didn't know that you were breaking code, and the tests saved you.
Hallelujah!
Learn about TDD to start, and then begin integrating it into your workflow. If you use the methodologies enough, you'll find that they become second nature and you'll start framing all of your development tasks within that framework.
Also, start using the J-Unit (or X-Unit) framework for your language of choice.
One word, practice! There is some overhead with doing TDD and the way to overcome it is to practice and make sure you are using tools to help the process. You need to learn the tools like the back of your hand. Once you learn the tools to go along with the process you are learning, then it will click and you will get fluent with writing tests first to flush the code out. Then you will be "test infected".
I answered a question similar to this a while back. You may want to check it out also. I mention some tools and explain learning TDD. Out of these tools, Resharper and picking a good mocking framework are critical for doing TDD. I can't stress learning these tools to go along with the testing framework you are using enough.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have been tasked with developing a document for internal testing standards and procedures in our company. I've been doing plenty of research and found some good articles, but I always like to reach out to the community for input on here.
That being said, my question is this: How do you take a company that has a very large legacy code base that is barely testable, if at all testable, and try to test what you can efficiently? Do you have any tips on how to create some useful automated test cases for tightly coupled code?
All of our new code is being written to be as loosely coupled as possible, and we're all pretty proud of the direction we're going with new development. For the record, we're a Microsoft shop transitioning from VB to C# ASP.NET development.
There are actually two aspects to this question: technical, and political.
The technical approach is quite well defined in Michael Feathers' book Working Effectively With Legacy Code. Since you can't test the whole blob of code at once, you hack it apart along imaginary non-architectural "seams". These would be logical chokepoints in the code, where a block of functionality seems like it is somewhat isolated from the rest of the code base. This isn't necessarily the "best" architectural place to split it, it's all about selecting an isolated block of logic that can be tested on its own. Split it into two modules at this point: the bulk of the code, and your isolated functions. Now, add automated testing at that point to exercise the isolated functions. This will prove that any changes you make to the logic won't have adverse effects on the bulk of the code.
Now you can go to town and refactor the isolated logic following the SOLID OO design principles, the DRY principle, etc. Martin Fowler's Refactoring book is an excellent reference here. As you refactor, add unit tests to the newly refactored classes and methods. Try to stay "behind the line" you drew with the split you created; this will help prevent compatibility issues.
What you want to end up with is a well-structured set of fully unit tested logic that follows best OO design; this will attach to a temporary compatibility layer that hooks it up to the seam you cut earlier. Repeat this process for other isolated sections of logic. Then, you should be able to start joining them, and discarding the temporary layers. Finally, you'll end up with a beautiful codebase.
Note in advance that this will take a long, long time. And thus enters the politics. Even if you convince your manager that improving the code base will enable you to make changes better/cheaper/faster, that viewpoint probably will not be shared by the executives above them. What the executives see is that time spent refactoring code is time not spent on adding requested features. And they're not wrong: what you and I may consider to be necessary maintenance is not where they want to spend their limited budgets. In their minds, today's code works just fine even if it's expensive to maintain. In other words, they're thinking "if it ain't broke, don't fix it."
You'll need to present to them a plan to get to a refactored code base. This will include the approach, the steps involved, the big chunks of work you see, and an estimated time line. Its also good to present alternatives here: would you be better served by a full rewrite? Should you change languages? Should you move it to a service oriented architecture? Should you move it into the cloud, and sell it as a hosted service? All these are questions they should be considering at the top, even if they aren't thinking about them today.
If you do finally get them to agree, waste no time in upgrading your tools and setting up a modern development chain that includes practices such as peer code reviews and automated unit test execution, packaging, and deployment to QA.
Having personally barked up this tree for 11 years, I can only assure you it's incredibly not easy. It requires a change all the way at the top of the tech ladder in your organization: CIO, CTO, SVP of Development, or whoever. You also have to convince your technical peers: you may have people who have a long history with the old product and who don't really want to change it. They may even see your complaining about its current state as a personal attack on their skills as a coder, and may look to sabotage or sandbag your efforts.
I sincerely wish you nothing but good luck on your venture!
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I get the concept of unit testing and TDD on a whole.
However, I'm still a little confused on what exactly unit testing frameworks are. Whenever I read about unit testing, it's usually an explanation of what it is, followed by "oh here are the frameworks for this language, i.e JUnit".
But what does that really mean? Are framework just a sort of testing library that allows programmers to write simpler/efficient unit tests?
Also, what are the benefits of using a framework? As I understand it, unit testing is done on small chunks of code at a time, i.e a method. However, I could individually write a test for a method without using a unit testing framework. Is it maybe for standardization of testing practices?
I'm just very new to testing and unit-testing, clarification on some basic concepts would be great.
A bit of a broad question, but I think there are certain thoughts that could count as as facts for an answer:
When 5, 10, 100, ... people go forward to "work" with the same idea/concept (for example unit testing) then, most likely, certain patterns respectively best practices will evolve. People have ideas, and by trial and error they find out which of those ideas are helpful and which are not.
Then people start to communicate their ideas, and those "commonly used" patterns undergo discussions and get further refined.
And sooner or later, people start thinking "I am doing the same task over and over again; I should write a program for me to do that".
And that is how frameworks come into existence: they are tools to support certain aspects of a specific activity.
Let's give an example: using a framework like JUnit, I can completely focus on writing test cases. I don't need to worry about accumulation of failure statistics; I don't need to worry how to make sure that really all my tests are executed when I want that to happen.
I simply understand how to use the JUnit framework; and I know how to further utilize JUnit test cases in conjunction with build systems such as gradle or maven - in order to have all my unit tests executed automatically; each time I push a commit into my source code management system for example.
Of course you can re-invent the wheel here; and implement all of that yourself. But that is just a waste of time. It is like saying: "I want to move my crop to the market - let's start by building the truck myself". No. You rent or buy a pre-build truck; and you use that to do what you actually want to do (move things around).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I've been working for years on my personal project, an operating system made from scratch. As you may imagine it's quite complicated stuff. The problem is that I've been working this from scratch many times. Meaning that at some point (quite advanced too, I had hard disk read/write and some basic networking), things were too confused and I decided to throw it all by the window and try again.
In the years I've learnt how to make the code look nicer, I read "Clean Code - A Handbook of Agile Software Craftsmanship" by Robert Martin and it helped a lot. I learnt to make functions smaller, organize things in classes (I used C, now C++) and namespaces, appropriate error handling with exceptions and testing.
This new approach however got me stuck at the point that I spend most of the time to check that everything is going well, that the code reads well, that is easy, well commented and tested. Basically I'm not making any relevant step from months. When I see my well-written code, it's difficult to add a new functionality and think "where should I put this? Have I already used this piece of code? What would be the best way to do this?" and too often I postpone the work.
So, here's the problem. Do you know any code writing strategy that makes you write working, tested, nice code without spending 90% of time at thinking how to make it working, tested and nice?
Thanks in advance.
Do you know any code writing strategy that makes you write working, tested, nice code without spending 90% of time at thinking how to make it working, tested and nice?
Yes, here.
Seriously, no. It is not possible to write good code without thinking.
When I see my well-written code, it's difficult to add a new functionality and think "where should I put this? Have I already used this piece of code? What would be the best way to do this?" and too often I postpone the work.
This is called "analysis paralysis". You might be interested in reading the "Good Enough Software" section of The Pragmatic Programmer. Your code doesn't have to be perfect.
Those things are widely discussed. To me this legendary blog entry be Joel Spolsky and the follow up discussion (Robert Martin answered this) everywhere an the web contains all the pro and cons and is still fun to read.
To get an idea here's a quote by Jamie Zawinski which appears in the post linked to above:
“At the end of the day, ship the fu****g thing! It’s great to rewrite your code and make it cleaner and by the third time it’ll actually be pretty. But that’s not the point—you’re not here to write code; you’re here to ship products.”
I suggest you give TDD (test driven development) a run.
In this context, you will write automated tests for each piece of functionality before implementing it, then you run the tests after completing the feature.
If the tests pass, then you are done, and can start another feature. As a bonus, the tests will collect over time, and you will soon have a test suite you can use for regression testing (to make sure you haven't broke anything while new coding); this addresses your fear of breaking things in the "nice code".
Also, TDD will let you focus on developing exactly what you need, not more, so it tends to lead to nicer and simpler design (especially in interfaces, since you have to think about interfaces before you start coding, so "thought" drives the interfaces, rather than "whatever happens to be handier when I'm coding it".)
However, be aware that applying automated tests to an OS may provide some amount of technical challenge!
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
When I get excited about a new feature I'm just about to implement or about a bug that I've just "understood", there is the urge to just jump into the code and get hacking. It takes some effort to stop myself from doing that and to write the corresponding test first. Later the test often turns out to be trivial 4-liner, but before writing it still there's the thought in back of a head, "maybe I can skip this one, this one time?" Ideally I'd like to get an urge to write test, and only then, perhaps, the code :)
What method (or way of thinking or mind trick or self-reward policy or whatever) do you use to help maintain the discipline? Or do you just practice it until it feels natural?
I like the instant feedback from the test, that's reward enough for me. If I can reproduce a bug in a test that's a good feeling, I know I'm headed in the right direction as opposed to guessing and possibly wasting my time.
I like working Test-First because I feel like it keeps me more in tune with what the code is actually doing as opposed to guessing based on a possibly inaccurate mental model. Being able to confirm my assumptions iteratively is a big payoff for me.
I find that writing tests helps me to sketch out my approach to the problem at hand. Often, if you can't write a good test, it means you haven't necessarily thought enough about what it is that you're supposed to be doing. The satisfaction of being confident that I know how to tackle the problem once the tests are written is rather useful.
I'll let you know when I find a method that works. :-)
But seriously, I think your "practice until it feels natural" comment pretty much hits the nail on the head. A 4 line test may appear trivial, but as long as what you are testing represents a real failure point then it is worth doing.
One thing I have found to be helpful is to include code coverage validation as part of the build process. If I fail to write tests, the build will complain at me. If I continue failing to write tests, the continuous integration build will "error out" and everyone nearby will hear the sound I have wired to the "broken build" notification. After a few weeks of "Good grief... You broke it again?", and similar comments, I soon started writing more tests to avoid embarrassment.
One other thing (which only occurred to me after I had submitted the answer the first time) is that once I really got into the habit of writing tests first, I got great positive reinforcement from the fact that I could deliver bug-fixes and additional features with much greater confidence than I could in my pre-automated-test days.
Easiest way I've found is to just use TDD a lot. At some point, writing code without unit tests becomes a very, very nervous activity.
Also, try to focus on interaction or behavioral testing rather than state-based testing.
wear a green wristband
1) You pair with somebody else in your team. One person writes the test, the other implements.
It's called "ping-pong" pairing.
Doing this will force you to discuss design and work out what to do.
Having this discussion also makes it easier to see what tests you're going to need.
2) When I'm working on my own, I like to try out chunks of code interactively. I just type them in at the ruby prompt. When I'm experimenting like this I often need to set up some data for experimenting with, and some printout statements to see what the result is.
These little, self-contained throwaway experiments are usually:
a quick way to establish the feasibility of an implementation, and
good place to start formalising into a test.
I think the important part of keeping yourself in check as far as TDD is concerned is to have the test project set up properly. That way adding a trivial test case is indeed trivial.
If to add a test you need to first create a test project, then work out how isolate components, when to mock things, etc, etc it gees into too hard basket.
So I guess it comes back to having unit tests fully integrated into your development process.
When I first started doing TDD around 2000, it felt very unnatural. Then came the first version of .net and the JUnit port of NUnit, and I started practice TDD at the Shu level (of Shu-Ha-Ri), which meant test (first) everything, with the same questions as yours.
A few years later, at another workplace, together with a very dedicated, competent senior developer, we took the steps necessary to reach the Ha level. This meant for example, not blindly starring at the coverage report, but question "is this kind of test really useful, and does it add more value than it costs?".
Now, at another workplace, together with yet another great colleague, I feel that we're taking our first steps towards the Ri level. For us that currently means a great focus on BDD/executable stories. With those in place verifying the requirements at a higher level, I feel more productive, since I don't need to (re-)write a bunch of unit tests each time a class' public interface needs to change, replace a static call with an extension method, and so on.
Don't get me wrong, the usual TDD class tests still is used and provides great value for us. It's hard to put in words, but we're just so much better at "feeling" and "sensing" what tests makes sense, and how to design our software, than I was capable of ten years ago.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
As I've increasingly absorbed Agile thinking into the way I work, yagni ("you aren't going to need it") seems to become more and more important. It seems to me to be one of the most effective rules for filtering out misguided priorities and deciding what not to work on next.
Yet yagni seems to be a concept that is barely whispered about here at SO. I ran the obligatory search, and it only shows up in one question title - and then in a secondary role.
Why is this? Am I overestimating its importance?
Disclaimer. To preempt the responses I'm sure I'll get in objection, let me emphasize that yagni is the opposite of quick-and-dirty. It encourages you to focus your precious time and effort on getting the parts you DO need right.
Here are some off-the-top ongoing questions one might ask.
Are my Unit Tests selected based on user requirements, or framework structure?
Am I installing (and testing and maintaining) Unit Tests that are only there because they fall out of the framework?
How much of the code generated by my framework have I never looked at (but still might bite me one day, even though yagni)?
How much time am I spending working on my tools rather than the user's problem?
When pair-programming, the observer's role value often lies in "yagni".
Do you use a CRUD tool? Does it allow (nay, encourage) you to use it as an _RU_ tool, or a C__D tool, or are you creating four pieces of code (plus four unit tests) when you only need one or two?
TDD has subsumed YAGNI in a way. If you do TDD properly, that is, only write those tests that result in required functionality, then develop the simplest code to pass the test, then you are following the YAGNI principle by default. In my experience, it is only when I get outside the TDD box and start writing code before tests, tests for things that I don't really need, or code that is more than the simplest possible way to pass the test that I violate YAGNI.
In my experience the latter is my most common faux pas when doing TDD -- I tend to jump ahead and start writing code to pass the next test. That often results in me compromising the remaining tests by having a preconceived idea based on my code rather than the requirements of what needs to be tested.
YMMV.
Yagni and KISS (keep it simple, stupid) are essentially the same principle. Unfortunately, I see KISS mentioned about as often as I see "yagni".
In my part of the wilderness, the most common cause of project delays and failures is poor execution of unnecessary components, so I agree with your basic sentiment.
The freedom to change drives YAGNI. In a waterfall project, the mantra is control scope. Scope is controlled by establishing a contract with the customer. Consequently, the customer stuffs all they can think of in the scope document knowing that changes to scope will be difficult once the contract has been signed. As a result, you end up with applications that has a laundry list of features, not a set of features that have value.
With an agile project, the product owner builds a prioritized product backlog. The development team builds features based on priority i.e., value. As a result, the most important stuff get built first. You end up with an application that has features that are valued by the users. The stuff that is not important falls off the list or doesn't get done. That is YAGNI.
While YAGNI is not a practice, it is a result of the prioritized backlog list. The business partner values the flexibility afforded the business given that they can change and reprioritized the product backlog from iteration to iteration. It is enough to explain that YAGNI is the benefit gained when we readily accept change, even late in the process.
The problem I find is that people tend to bucket even writing factories, using DI containers (unless you've already have that in your codebase) under YAGNI. I agree with JB King there. For many people I've worked with YAGNI seems to be the license to cut corners / to write sloppy code.
For example, I was writing a PinPad API for abstracting multiple models/manufacturers' PINPad. I found unless I've the overall structure, I can't write even my Unit Tests. May be I'm not a very seasoned practioner of TDD. I'm sure there'll be differing opinions on whether what I did is YAGNI or not.
I have seen a lot of posts on SO referencing premature optimization which is a form of yagni, or at least ydniy (you don't need it yet).
I don't see YAGNI as the opposite of quick-and-dirty, really. It is doing just what is needed and no more and not planning like the software someone writes has to last 50 years. It may come rarely because there aren't really that many questions to ask around it, at least to my mind. Similar to the "don't repeat yourself" and "keep it simple, stupid" rules that become common but aren't necessarily dissected and analyzed in 101 ways. Some things are simple enough that it is usually gotten soon after doing a little practice. Some things get developed behind the scenes and if you turn around and look you may notice them may be another way to state things.