Test Driven Dev
-
Josh Smith wrote:
I suppose that I would need to see a well designed test suite to be convinced that it proffers advantages above and beyond asserts and null checks.
Well, some advice, if I may. Decouple the need for a "well designed test suite" from the advantages of TDD. Also, don't buy into TDD whole hog--it needs to meet your requirements, budget, timeframe, it needs to be part of the planning for the product lifecycle. Not being happy with nUnit, I wrote my own test framework. Am I happy with it? Mostly, but there's a few little nits that unfortunately would require pretty much a complete rewrite, argh (let me tell you about ApplicationDomain and marshalling across app domain boundaries and serializable classes one day). From my own experiences, I can tell you there is great pleasure in making a change to, say, my persistence service to add automatic client synchronization, and knowing when I'm done that I can rerun my unit tests to verify that all the other functionality is still working. I will say one thing though--I still can't write the test first. I have to write at least stubs for the actual code and then write the tests. It's because I do a lot of architecting when writing the code itself, as, ironically, I haven't found any decent code architecture/design tools--tools that don't hinder the creative process. Marc Pensieve
Some people believe what the bible says. Literally. At least [with Wikipedia] you have the chance to correct the wiki -- Jörgen Sigvardsson
People are just notoriously impossible. --DavidCrow
Marc Clifton wrote:
I will say one thing though--I still can't write the test first. I have to write at least stubs for the actual code and then write the tests. It's because I do a lot of architecting when writing the code itself, as, ironically, I haven't found any decent code architecture/design tools--tools that don't hinder the creative process.
We recently had a break out discussion at our local user group over the topic of TDD, and this was one of things covered. The one thing I try to keep in mind is: "Describe what it needs to do, not how it needs to do it". You really have to change the way you think about writing code, if you can't do that, there will be major hurdles you will have to deal with later on. My 2 cents. :-)
- Nick Parker Microsoft MVP - Visual C#
My Blog | My Articles -
Judah Himango wrote:
This not only saves time (you don't have to wait for your big rich client to startup, connect to your server, then try out the new functionality), but it also is more comprehensive, covering things that would be difficult to test, or so rare occurring that one would rarely run into it in the real world.
this comment strikes me, since a lot of my programming work can be described as a thick client. i read a small amount about TDD for a program that connects to a database, and was left with the impression that you had to setup a fake database for the tests, etc. i just have no "world view" of how to approach TDD *shrug* from your experience, or if anyone else has any experience, let me explain one area of code i develop and maintain. we have data files (flat files, complex format) and i have a set of code to render these data files as HTML, to show the user. there is a specification, with pages of rules, describing how and when data must be placed into the HTML X| its a rather nasty specification to work with. the rendering code is nice and modular, but complex. most of the bits are very simple (insert a bold word) but a few are complex (parse the data file into logical blocks depending on its format). given the input is a record from a database and the output is a piece of HTML i get the feeling TDD is going to be a set of input files and a set of "valid outputs", and basically a long list of "input A gives output B" tests, which will be a pile of work to setup. *wonders* as i am thinking this through i may be making progress in understanding this. would a TDD approach be a series of input files, ranging from very basic to very complex, so you start by satisfying the very basic tests first, slowly working up to the complex tests? or am i still missing the core idea at work here? zen is the art of being at one with the two'ness
feline_dracoform wrote:
was left with the impression that you had to setup a fake database for the tests, etc.
It depends. Here's how it goes: you write a test for a function. Then you realize that your function calls into something you don't want to test; maybe it calls into your data layer, or maybe it shows a dialog, etc. Since you're just testing this function, you want the test to be small and precise; you don't need to test your whole data layer; in fact, you want your test to execute instantly, you don't want it to even connect to your data layer. So here's where the mock objects come in; they let you mock your data layer or other resource you don't want this small test to encompass. Let's take a real example. You have a function called UpdateRecord that takes a patient record, changes the patient's last check-in time, and saves it to your data layer (which then saves it to the database or some other persistent storage).
public void UpdateRecord(Patient patientToUpdate)
{
patientToUpdate.LastCheckInTime = DateTime.Now;
dataLayer.SavePatient(patientToUpdate);
}To really test this function, you'll want to verify that the date was set correctly and that it gets saved back to the data layer. How in the world can you do this, you might wonder. :) You can do this by refactoring your code to make it more modular and unit-testable; basically, making the function be more of a "unit" by itself, rather than relying on internals and variables. So let's first refactor the function so that we supply the date to the function, so that we can verify it's getting set correctly.
public void UpdateRecord(Patient patientToUpdate, DateTime updateTime)
{
patientToUpdate.LastCheckInTime = updateTime;
dataLayer.SavePatient(patientToUpdate);
}With that, we can now write a simple test that verifies the patient's LastCheckInTime is set correctly.
[Test] // The Test attribute is an attribute in an NUnit assembly that lets unit testing frameworks know this function is a test function
public void UpdateRecordShouldSetCheckinTime()
{
Patient patient = new Patient();
DateTime checkinTime = DateTime.Now();
myFoo.UpdateRecord(patient, checkinTime);// Assert class is a class in an NUnit assembly that allows a test to pass or fail based on some condition. Assert.AreEqual(checkinTime, patient.LastCheckinTime, "The UpdateRecord method didn't set the last checkin time of the patient.");
}
Now, we also nee
-
Judah Himango wrote:
Another great that is you can fix a bug, then write a test for it to ensure the bug never happens again. Moreover, you can write a feature or bug fix, then test it completely from code. Forget the whole code/run/restart dance; you can test a feature completely by running tests.
I always thought unit testing was for testing methods of a single class? How do you test features/bugs that span multiple modules? Do you still use NUnit? Regards Senthil _____________________________ My Blog | My Articles | My Flickr | WinMacro
Tests are for individual methods, yes. If the method depends on other objects, you plug in mock objects in place of those dependencies. This works; I actually did this for a big feature where we run multiple background threads which then report to a UI thread to update the UI. The whole feature was built for unit testing from the beginning, and I haven't had a single bug in it yet (not saying it won't have any bugs, but I feel pretty confident about the quality of the code). See my reply to feline_dracoform for more info.
Tech, life, family, faith: Give me a visit. I'm currently blogging about: Messianic Instrumentals (with audio) The apostle Paul, modernly speaking: Epistles of Paul Judah Himango
-
I don't understand the hype surrounding TDD. Many people tell me that it's the greatest thing since sliced bread, but I've never used it and I get by just fine. According to the "Best Practices" commitee at my current client, TDD is really important. I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines), and there isn't a line of test code involved, except for Debug.Assert()s and checks for null. The apps work famously and there are hardly ever any bugs reported, maybe three or four minor tweaky issues have cropped up since I've been there (8 months). So, why on Earth should I spend a large amount of my time building tests? I just don't see the benefit. :josh: My WPF Blog[^]
The real positive usage of TDD are when you need to change an implementation -- You will very quickly be informed of breaking any functionality (if the interface is tested throughly). But in your case, you do not have any real usage of it right now but if you are the maintainer in a couple of years down the road... You will curse your younger self for being soo narrow minded... I do see one drawback -- A TDD gives a false sense of security... Just because the test project doesn't break, doesn't say that everything works (as all to many seems to belive). rgds /Jonas
-
A bit off topic, but...
Josh Smith wrote:
I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines)
That's all? Just 35K lines? The project we just EOL'd was over 675,000 lines, and there were only two programmers working on it. Our current project is over 175,000 lines, and it's only six months in development with one programmer working on it (me). Then there's the project where we're writing a very small piece of a much larger system, and we have over 300,000 lines invested in that (again, just two programmers). 35K lines? I'm sorry, but I'm laughing my ass off... :)
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001Be nice, even the longest journey starts with a single step...
There's always someone bigger around the corner...
Usually it's my evil twin:cool:
-
Roger J wrote:
"you" in this case is you and your QA team and everyone else that is responsible for delivering a solid app.
For better or worse, I am the only person involved with creating this application suite. That makes testing it easier, in some ways, because when a feature is added I have a good idea of what was effected.
Roger J wrote:
the wole point of unittesting is to spend _less_ time writing test than you would spend manually testing it by clicking around in the application.
No matter how many unit tests I were to write, I still would need to test it by clicking around. I wouldn't feel comfortable just creating a build, checking that there are no testing failures, and then shipping the assemblies off to be packaged. Empirical testing, in my opinion, can never be replaced with automation. I suppose that if I were leading a dev team I'd require people to create unit tests, especially if I didn't know the team members. But for an app that I build without anyone else interfering, I still can't see it as a justifiable way to spend time. That's just me, I suppose. :josh: My WPF Blog[^]
As soon as you're not the only one modifying it, and you need someone else to help you on modifications to some segement you wrote, or you need to pass it off to someone else entirely, the value of TDD would become very apparent. Modifying a line of code inside a function or procedure embedded within the bowels of a code body is always nerve-wracking, especially for someone who didn't write it to begin with (and in my case, I find it so even if I did write it but it was long enough ago that I can't downright remember all the ins and outs... after 15 years of developing applications, even the ones I did last year are hard to remember all the details of). With TDD, I modify the line that I *think* I need to modify, run the tests, and I'll see instantly whether I broke something elsewhere that I never would have imagined. In fact, I can use TDD to help me identify a better way to make a modification in these cases. The most difficult thing I find with TDD is deciding when is enough... it's tempting to test everything but that will never end. And you don't want to write tests in a way that will break everything if you have a design change. So it's as much of a design skill as writing the code itself. It's also a great confidence builder as you see that the tests are actually passing and continue to pass as you build your app.
-
I don't understand the hype surrounding TDD. Many people tell me that it's the greatest thing since sliced bread, but I've never used it and I get by just fine. According to the "Best Practices" commitee at my current client, TDD is really important. I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines), and there isn't a line of test code involved, except for Debug.Assert()s and checks for null. The apps work famously and there are hardly ever any bugs reported, maybe three or four minor tweaky issues have cropped up since I've been there (8 months). So, why on Earth should I spend a large amount of my time building tests? I just don't see the benefit. :josh: My WPF Blog[^]
I don't think TDD is making a lot of sense in a single developer situation, but rather with medium-big projects that can be changed over time by different devs. I mean, it might be straight forward for you to just build the application and tweak the bugs, but it might be difficult for someone else to tweak your app. Also tests are good in the refactoring process, you just run the suite of tests after you made the refactoring, to see if what you did to improve the readability of the code didn't change any functionality. ---------- Siderite
-
Yeah, I don't think its meant to replace Empirical testing but to enhance it. Its your first line of defense when refactoring. As said before you can use it to at least ensure that nothing major was broken. But I find that it helps to start with it. Plugging it in after the fact could be monumentous. This statement is false.
Every body is talking about TDD but it seems that TOAD is valid only Java and .NET . What about GUI programing ? What about multithreading? What about C++ ? Can the TDD be used in these situations also ?
-
A bit off topic, but...
Josh Smith wrote:
I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines)
That's all? Just 35K lines? The project we just EOL'd was over 675,000 lines, and there were only two programmers working on it. Our current project is over 175,000 lines, and it's only six months in development with one programmer working on it (me). Then there's the project where we're writing a very small piece of a much larger system, and we have over 300,000 lines invested in that (again, just two programmers). 35K lines? I'm sorry, but I'm laughing my ass off... :)
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001John Simmons / outlaw programmer wrote:
35K lines? I'm sorry, but I'm laughing my ass off...
Good for you. :josh: My WPF Blog[^]
-
Every body is talking about TDD but it seems that TOAD is valid only Java and .NET . What about GUI programing ? What about multithreading? What about C++ ? Can the TDD be used in these situations also ?
Robert Vukovic wrote:
What about GUI programing ? What about multithreading? What about C++ ?
TDD can be applied to any programming language or situations. in my development world, we do gui, multithreading, C++, multiprocess. for the minor (play) programming of the original post (30K lines is barely getting started) with a single developer who does all aspects of product design, development and deployment, one can get away with not writing tests (though it is not a good idea). empirical testing is not a good way to test. it is inherently error prone (humans are very poor at repetitive tasks) and usually skips tests that the user simply “believes” cannot be broken (but invariably are broken). We’ve automated all of our testing (gui included) so that you are assured that the changes you have made work in the current source set. Without tests you cannot refactor with confidence (in fact according to “refactoring to patterns”, Kerievsky; you cannot refactor without a complete set of unit tests). TDD is also about writing the test before you write the code. The test should fail when you try to run the test (as the code “should not” exist yet), but if the test passes, then you don’t need to write any code. It also helps in finding those corner cases as you can write the crazy tests before you code and get an idea of how to solve the corner cases while you’re writing the main algorithm. This allows for you to provide a generic algorithm without all the “if..else” kludges for the corner cases. Asserts are not a testing methodology, they are a debugging methodology. Asserts are supposed to be used to test setup conditions and assumptions in the code. They are not a good tool for testing code. Automated unit and regression testing are the best way at this point. Formal proofs are the best method, in theory you would not even have to run tests if one could provide a formal proof of the application, but we’re a long way away from that (maybe never for complete applications). TDD is not a silver bullet (there are NO software silver bullets, see IEEE Queue, I think june ’06 issue). i don’t like the hype around it either. Nothing will beat good programming practices and discipline. TDD is a good practice. schleprock
Robert Vukovic wrote:
What about GUI programing ? What about multithreading? What about C++ ?
-
Josh Smith wrote:
I just don't see the benefit.
It's only a benefit if you can test against something, eg some algorhithm.**
xacc.ide-0.2.0 preview - Now in 100% C# goodness
**
leppie wrote:
It's only a benefit if you can test against something, eg some algorhithm.
absolutely not true. one small example, your end user uses the output from your application to automate something else, they expect your output to be in a specific order with a particular syntax. if you don't want to piss off your end user, you test that the output is correct anytime you change your application. testing is about ensuring that your code base at the time of compilation is acting in a fashion that your end user is expecting. while that does include testing of algorithmic correctness, it also includes correct output (which could be font, color, placement in the window, ...) for a given input. it should also include detecting and handling error conditions in a resonable way. simply exiting out unexpectedly on any error is NOT a resonable way of handling error conditions (and that is not necessarily algorithmic). schleprock
-
I support your skepticism. The core of TDD is writing tests before you write the code. I've found this tends to lead to inferior code since the resulting code tends to be written to be easily tested, not to solve the problem of the larger system. The bigger problem with TDD is that it assumes you have correctly anticipated all the requirements of the code and how the code will actually be used. Having said this, do be careful not to throw the baby out with the bath water. While I reject the core notion of TDD--writing tests first--automated testing for modules is a VERY good practice. This allows you to add tests as failure modes become known and a good way to regress any changes you make to the code. (One problem in TDD is finding that a fundamental code change will greatly improve the application but will render the tests invalid as written. This WILL happen often. The temptation is to compromise the code so the tests either don't have to be rewritten or the rewrite is minimal. If you aren't careful, you end up creating an application that passes all the tests, but doesn't solve the customer's problem. As a developer, we may proclaim this simply won't happen, but tell that to the people writing your paychecks.) Anyone who thinks he has a better idea of what's good for people than people do is a swine. - P.J. O'Rourke
Joe Woodbury wrote:
(One problem in TDD is finding that a fundamental code change will greatly improve the application but will render the tests invalid as written. This WILL happen often. The temptation is to compromise the code so the tests either don't have to be rewritten or the rewrite is minimal. If you aren't careful, you end up creating an application that passes all the tests, but doesn't solve the customer's problem. As a developer, we may proclaim this simply won't happen, but tell that to the people writing your paychecks.)
you're not writing good tests. the unit tests should be very specific tests that should never change unless you re-architect the product. regression tests should test the output in a way that allows for change in the output without invalidating the test. for example, if the output from your application is textual but you don't care about the order in which the output appears, sort the output from the application and then check for correctness. you've now gotten rid of the ordering issue. if you're testing a gui and you don't care about button position, write the test to bypass choosing the button via x/y location and call the method directly. have a single test that triggers a button push via position and you only need to update that one test when the button gets moved. tests need to be written to ignore things that you don't care about and only test what you do care about. schleprock
-
I don't understand the hype surrounding TDD. Many people tell me that it's the greatest thing since sliced bread, but I've never used it and I get by just fine. According to the "Best Practices" commitee at my current client, TDD is really important. I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines), and there isn't a line of test code involved, except for Debug.Assert()s and checks for null. The apps work famously and there are hardly ever any bugs reported, maybe three or four minor tweaky issues have cropped up since I've been there (8 months). So, why on Earth should I spend a large amount of my time building tests? I just don't see the benefit. :josh: My WPF Blog[^]
I would tend to say that you don't see the benefit mostly because of the size of your team. When you have multiple people working on a code base, and a peppering of programmers of lesser skills, you needs something that can quickly throw red flags when a negative change ripples out. That said, it's just another tool which, when used correctly can be very beneficial. But unit tests are just like other code, crap in crap out. Great discussion. :)
Try code model generation tools at BoneSoft.com.
-
I don't understand the hype surrounding TDD. Many people tell me that it's the greatest thing since sliced bread, but I've never used it and I get by just fine. According to the "Best Practices" commitee at my current client, TDD is really important. I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines), and there isn't a line of test code involved, except for Debug.Assert()s and checks for null. The apps work famously and there are hardly ever any bugs reported, maybe three or four minor tweaky issues have cropped up since I've been there (8 months). So, why on Earth should I spend a large amount of my time building tests? I just don't see the benefit. :josh: My WPF Blog[^]
If you can write 35K lines of bug-free code, then TDD is not for you. But, as for the rest of us, . . . The thing is, I bet you actually wrote a lot of tests. In fact, I bet you wrote some of the same tests many times. You just didn't save them. TDD gives you a framework to keep all those snippets of test code you inevitably write, even when not doing TDD. I also agree with other posts that say that the value of TDD increases with the size of the team.
-
You never see the real advantage to it until you get a feature request that requires you to take the app appart and put it together again to do it right. With a large suite of tests you can be much more fearless doing things the right way even though they are high risk rather then slapping in a couple of hacks to get through this round of updates. It also defends against the ravages of time. If you have to make a change a year from now after you've been using xyz control library and the latest and greatest development techniques. The test library saves you from inadvertently breaking everything you've forgotten about in the meantime. [edit] Another advantage is coverage. When I worked at Dell, the only way we could get in the sub-thousand ASP errors per day were to write brutal automated tests that randomly clicked arond the site while entering random data in all the forms. All all that to get in the 0.0x% error rate. When you serve millions of pages a day, you get several one in a million events a day. [/edit]
I can imagine the sinking feeling one would have after ordering my book, only to find a laughably ridiculous theory with demented logic once the book arrives - Mark McCutcheon
-- modified at 15:46 Sunday 16th July, 2006
How was Dell? I noticed recently that they are hiring for a lot of development jobs.
Try code model generation tools at BoneSoft.com.
-
Every body is talking about TDD but it seems that TOAD is valid only Java and .NET . What about GUI programing ? What about multithreading? What about C++ ? Can the TDD be used in these situations also ?
Well, as with any methodology you need to use it and see how and where it works for you and your situation. It doesn't matter which language you choose, as the unit test is just a contract that the app must fulfill. Some automated tests can work against guis, but what works for me is keeping it simple. Writing unit tests for components and libraries to ensure you get what you expect. I disagree with the other fellow that empirical tests aren't good. I think you need to balance both, part of that is going to be usability and no automated system will tell you that, you need humans. As to threading, well, a unit test in a client/server setup would have one test prewritten for the client and one for the server. Then multiply the clients to test for load, but there will always be the obscure bug that they won't find, although they might display the symptom such as deadlocks. So while yer mileage may vary, I would start simple, and see what works for you, and go with it. This statement is false.
-
I don't understand the hype surrounding TDD. Many people tell me that it's the greatest thing since sliced bread, but I've never used it and I get by just fine. According to the "Best Practices" commitee at my current client, TDD is really important. I have built them a large suite of applications, based on a huge business object framework completely rolled from scratch (around 30-35k lines), and there isn't a line of test code involved, except for Debug.Assert()s and checks for null. The apps work famously and there are hardly ever any bugs reported, maybe three or four minor tweaky issues have cropped up since I've been there (8 months). So, why on Earth should I spend a large amount of my time building tests? I just don't see the benefit. :josh: My WPF Blog[^]
It doesn't sound to me that you're only anti-TDD. Sounds like you're saying you're anti-SQA in general. That's probably a separate discussion altogether. Honest, I had a hard time getting past the statement "I've never used it and I get by just fine." -- modified at 10:52 Wednesday 19th July, 2006
-
feline_dracoform wrote:
was left with the impression that you had to setup a fake database for the tests, etc.
It depends. Here's how it goes: you write a test for a function. Then you realize that your function calls into something you don't want to test; maybe it calls into your data layer, or maybe it shows a dialog, etc. Since you're just testing this function, you want the test to be small and precise; you don't need to test your whole data layer; in fact, you want your test to execute instantly, you don't want it to even connect to your data layer. So here's where the mock objects come in; they let you mock your data layer or other resource you don't want this small test to encompass. Let's take a real example. You have a function called UpdateRecord that takes a patient record, changes the patient's last check-in time, and saves it to your data layer (which then saves it to the database or some other persistent storage).
public void UpdateRecord(Patient patientToUpdate)
{
patientToUpdate.LastCheckInTime = DateTime.Now;
dataLayer.SavePatient(patientToUpdate);
}To really test this function, you'll want to verify that the date was set correctly and that it gets saved back to the data layer. How in the world can you do this, you might wonder. :) You can do this by refactoring your code to make it more modular and unit-testable; basically, making the function be more of a "unit" by itself, rather than relying on internals and variables. So let's first refactor the function so that we supply the date to the function, so that we can verify it's getting set correctly.
public void UpdateRecord(Patient patientToUpdate, DateTime updateTime)
{
patientToUpdate.LastCheckInTime = updateTime;
dataLayer.SavePatient(patientToUpdate);
}With that, we can now write a simple test that verifies the patient's LastCheckInTime is set correctly.
[Test] // The Test attribute is an attribute in an NUnit assembly that lets unit testing frameworks know this function is a test function
public void UpdateRecordShouldSetCheckinTime()
{
Patient patient = new Patient();
DateTime checkinTime = DateTime.Now();
myFoo.UpdateRecord(patient, checkinTime);// Assert class is a class in an NUnit assembly that allows a test to pass or fail based on some condition. Assert.AreEqual(checkinTime, patient.LastCheckinTime, "The UpdateRecord method didn't set the last checkin time of the patient.");
}
Now, we also nee
thank you for a thoughtful reply. i have saved it out and will read it / think about it, when i am no longer snowed under with work *rolls eyes*
zen is the art of being at one with the two'ness