📄 unittests.html
字号:
<head><title>Unit Tests</title></head><body><h1><img src="logo.gif"> Unit Tests</h1>See also: <a href="http://c2.com/cgi/wiki?UnitTestExamples">UnitTestExamples</a>, <a href="http://c2.com/cgi/wiki?UnitTestingCostsBenefits">UnitTestingCostsBenefits</a>.
<p><hr>
<p><em>Are we confusing tradition with necessity?</em>
<p>Perhaps the distinction between an <a href="http://c2.com/cgi/wiki?AcceptanceTest">AcceptanceTest</a> (nee "functional test") and a <a href="http://c2.com/cgi/wiki?UnitTest">UnitTest</a> is not what they test or how they're done, but in who they satisfy. The acceptance test makes the customer satisfied that the software provides the business value that makes them willing to pay for it. The unit test makes the programmer satisfied that the software does what the programmer thinks it does.
<p>It could be that some people confuse traditions with the actual definition of the tests. One might say, for example, "A unit test is testing an individual class in isolation," or "An acceptance test tests the entire program." That would be wrong. They are not the definitions, just traditions resulting from the forces that act upon you when you are doing testing. There is absolutely nothing wrong with the programmer writing a so-called unit test that tests the whole program, or with the customer defining a functional test that stubs out part of the system. It's up to the people doing it to weigh the costs and benefits, not to be arbitrarily constrained to tradition.
<p>However, some authors such as <a href="http://c2.com/cgi/wiki?MartinFowler">MartinFowler</a> and MatthewFoemmel<a href="http://c2.com/cgi/wiki?edit=MatthewFoemmel">?</a> believe that "Unit tests are written by developers and typically test an individual class or small group of classes." <a href="http://www.martinfowler.com/articles/continuousIntegration.html#N222">http://www.martinfowler.com/articles/continuousIntegration.html#N222</a> It may be that the authors are providing definitions or it may be that they are acknowledging a traditional understanding of the terms. In any case, <a href="http://c2.com/cgi/wiki?MartinFowler">MartinFowler</a> would probably be the first to say do what works and not be constrained to traditions when they do not serve well.
<p><em>[<a href="http://c2.com/cgi/wiki?DoBothUnitAndAcceptanceTests">DoBothUnitAndAcceptanceTests</a>.]</em>
<p><hr>
A more complete definition of <a href="UnitTests.html">UnitTests</a> in the traditional sense can be found in <a href="http://c2.com/cgi/wiki?CodeComplete">CodeComplete</a>, chapter 25.
<p><hr>
<a href="UnitTests.html">UnitTests</a> are programs written to run in batches and test classes. Each typically sends a class a fixed message and verifies it returns the predicted answer.
<p><a href="UnitTests.html">UnitTests</a> are a key component of software engineering, and the <a href="ExtremeProgramming.html">ExtremeProgramming</a> discipline leverages them to permit easy code changes. Developers write tests for every class they produce. The tests are intended to test every aspect of the class that could conceivably not work. (Do test adding and removing, don't test accessors.)
<p>To cure a common case of industry confusion, read <a href="http://c2.com/cgi/wiki?UnitTestsDefined">UnitTestsDefined</a> before the following.
<p>Key here is to <a href="http://c2.com/cgi/wiki?CodeUnitTestFirst">CodeUnitTestFirst</a>.
<p><a href="UnitTests.html">UnitTests</a> are all combined into a huge suite of tests, using <a href="KentBeck.html">KentBeck</a> 's <a href="http://c2.com/cgi/wiki?TestingFramework">TestingFramework</a>. When developers go to release new code, they run all the unit tests, not just theirs, on the integration machine. The tests <strong>must</strong> run at 100%. If any test fails, they figure out why and fix the problem. The problem certainly resides in something they did ... since they know the tests ran at 100% the last time anything was released.
<p>Of course, sometimes the tests let something slip through. When that happens, developers unconditionally enhance the unit tests so that that problem, and any similar one that comes to mind, won't happen again.
<p>C3 has over 1300 unit tests, performing over 13,000 individual checks. They run in about 10 minutes in <a href="http://c2.com/cgi/wiki?VisualWorks">VisualWorks</a>.
<p>See also <a href="FunctionalTests.html">FunctionalTests</a>.
<p>--<a href="RonJeffries.html">RonJeffries</a>
<p>When using a Relational DB for persistence, a universally supported unit test framework which is underused is using the database's <a href="http://c2.com/cgi/wiki?RelationalIntegrity">RelationalIntegrity</a> checks.
--<a href="http://c2.com/cgi/wiki?MarkSwanson">MarkSwanson</a>
<p><a href="http://c2.com/cgi/wiki?ProductionCode">ProductionCode</a> differs from <a href="http://c2.com/cgi/wiki?UnitTest">UnitTest</a> code per <a href="http://c2.com/cgi/wiki?ResilienceVsAnticipation">ResilienceVsAnticipation</a>.
<p><hr>
<p><a href="http://c2.com/cgi/wiki?IsUnitTestingExtreme">IsUnitTestingExtreme</a> ? I can understand the idea that writing the
functional tests first, then coding to them, is good. But what's
'extreme' about building monster unit-test scaffolds?
<p><em>It's </em>extreme<em>ly comforting when you see the <a href="http://c2.com/cgi/wiki?GreenBar">GreenBar</a>.</em> :o)
<p><hr>
I am just starting XP with unit tests in my current project. For new functionality that works fine, yet. What should I do with the old code? Of course I can磘 end up writing all the necessary tests. If I have to maintain code, I want to start writing unit tests as far I could. But the parts from the "old" code could not be used for writing special test cases, because it is not well structured. So I could refactor, but if I start doing that, I end up refactoring the whole project. Also I fear that the new better code has errors somewhere. Of course that's one of the good reasons for automated tests, that I can refactor without fear. But before that I need them. My little experiences show me, that writing automated tests makes better code too. But the practical difficulties are dragging me down. Maybe someone has some good advice or a few motivating words.
<p>...and I have a question about the C3 project. The tests run in 10 minutes. Surely you don磘 have data im- or exports. But if you have to test all the cases against a database, how can you end up in such a short time? And how about testing the GUI? Are you testing a window without opening it?
<p>--<a href="http://c2.com/cgi/wiki?SebastianPetzelberger">SebastianPetzelberger</a>
<hr>
We have data imports and exports. We have a few tests that go to the database, quite a few more that test file reads and writes. Most of the tests that do this we do against internal streams that do not do I/O. Then it is sufficient to have just a few tests that actually test the gateway to the database or the connection to the file system.
<p>We do some testing of GUIs without opening them. Our system does not have many GUIs, so we do not have very much intelligent to say about testing them. Of course, if you have kept the model very separate from the GUI, most of the testing can be done on the model side.
<p>For bringing old code into maintenance, I only know of two choices, for areas you need to begin changing: write the tests, painfully, and know whether your maintenance worked. Or don't write the tests, and be uncertain. Comprehensive functional tests can help, but will be slower and less immediate. Sorry. --<a href="RonJeffries.html">RonJeffries</a>
<p><hr>
When I first heard about some of these practices, I wanted to apply them but I was in the same boat: large code base, no <a href="UnitTests.html">UnitTests</a>. It is easy to get frustrated and think that it is all or nothing.. that you either go back, refactor and test the whole thing or you are doomed. The fact is, by starting testing, even late, you are better off than many other people who haven't. One step at a time.. As Ron says, just do it as you need it in maintenance. I've discovered that going back and attempting to write <a href="UnitTests.html">UnitTests</a> for legacy code is a good impetus for refactoring. True enough, it is tough sometimes to get enough of a handle on something to start testing it.
<p>I had one case where I had some logic in a GUI COM control which really should have been in a domain class. Unit testing a GUI COM control is pointless, so I ended up doing ArchitecturalSubstitution<a href="http://c2.com/cgi/wiki?edit=ArchitecturalSubstitution">?</a>. I duplicated the logic in a new class by writing <a href="UnitTests.html">UnitTests</a> first, and I kept compiling the new class into the application also, calling the methods on the new object and the control in parallel and verifying that they did the same thing. When I saw, through interaction with the live app, that the new class was doing what I wanted, I dropped the calls to the control and deleted the methods, leaving the calls to the new class. I now had a new class with tests. At each point in the process, I asked myself: "What is the smallest step that I can take towards the goal that keeps everything working?" One could say that the legacy code was the spec for the new code. Of course, now that the tests exist, I can refactor the hell out of it fearlessly.
<p>-- <a href="http://c2.com/cgi/wiki?MichaelFeathers">MichaelFeathers</a>
<p><hr>
Many thanks for your answers. Now I have a few good ideas to move on.
(This Wiki-Concept is great.)--<a href="http://c2.com/cgi/wiki?SebastianPetzelberger">SebastianPetzelberger</a>
<hr>
I think much of my answer is in what Mike said above but I don't understand it fully. My developers are writing unit tests for their classes and their COM components and that is fairly easy. They write an MFC test application that uses the COM control or component and just calls its methods and such. Now in my case, I am doing the GUI. The GUI COM app is a Java or MFC/C++ Windows Application. How do I write <a href="UnitTests.html">UnitTests</a> for it? How do I drive the application? Essentially users would just point and click. They would select things off menus and so forth. I guess this a general question of how you write <a href="UnitTests.html">UnitTests</a> for Windows GUI applications in <a href="ExtremeProgramming.html">ExtremeProgramming</a>.
--<a href="http://c2.com/cgi/wiki?SamGentile">SamGentile</a>
<p><em>In general, <a href="http://c2.com/cgi/wiki?GuiTesting">GuiTesting</a> is difficult.</em>
<p>For several reasons, it is a good idea to design GUI applications
to communicate with a back-end via some command language.
<UL><li> Doing so allows power users to easily automate tasks.
<li> The command language can be used to automate integration testing.
<li> The design of the command language creates a clear divide between the GUI code and the object model.
<li> If a bug is discovered, then the command stream can be recorded, greatly simplifying fault analysis.
</UL>--<a href="http://c2.com/cgi/wiki?KevinCline">KevinCline</a>
<p><hr>
There are tools that record keystrokes and mouse clicks and recognize common controls. These tools can be used for scripting GUI tests. SQA Robot is an example.
<hr><a href="http://c2.com/cgi/wiki?CayteLindner">CayteLindner</a>
<hr>
<p>I just finished a large application that had thousands of unit tests. Unfortunately, it took hours to run all the tests so immediate complete testing wasn't possible. As well it was often the combination of development changes that caused tests to fail. But commitment to the process can help regain confidence in the extreme testing.
<p>How did you deal with Business pressures towards the end of development cycles that discourage non-core development work?
<p>Also, did you introduce tests late in development that identified unforseen problems. If so did your fixes to those problems break other things. In other words how did you fight the "if it ain't broke don't fix it attitude."
<p>Cheers,
Kieran
<p>Please say more about the business pressures question, I can't grok it.
<p>More on the other in a bit.
<hr>
It is the <a href="UnitTests.html">UnitTests</a> themselves that allow you to get away from the "if it ain't broke don't fix it attitude." You must be able to modify anything in the entire system at anytime. Ah the freedom of it! The only way you can do that is to require the <a href="UnitTests.html">UnitTests</a> be run before any code is released at a <a href="http://c2.com/cgi/wiki?SingleReleasePoint">SingleReleasePoint</a>. And to do that they must run in a reasonable amount of time. I remember once on C3 our <a href="UnitTests.html">UnitTests</a> were taking 25 minutes to run. When <a href="KentBeck.html">KentBeck</a> came in he was <em>appalled</em>. He immediately sat down and trimmed and optimized our tests back down to one minute. The <a href="http://c2.com/cgi/wiki?VcapsProject">VcapsProject</a> has been through this twice already in 6 months. As soon as the <a href="UnitTests.html">UnitTests</a> take over 10 minutes to run you are in big big trouble and immediately need to optimize or remove redundant tests. And they are not just for releasing, you must be unafraid to just fire them off while you are working.--<a href="DonWells.html">DonWells</a>
<hr>
I also wanted to say something about coming upon a huge system with no <a href="UnitTests.html">UnitTests</a> written. This describes the <a href="http://c2.com/cgi/wiki?VcapsProject">VcapsProject</a> exactly. I will tell you what I told Ford. "<em>Unit test suites evolve over time. You constantly add tests for things you could never imagine going wrong. If you do not start adding <a href="UnitTests.html">UnitTests</a> today then one year from now you will still not have a good unit test suite.</em>" By adding unit tests for 40% of the <a href="http://c2.com/cgi/wiki?VcapsProject">VcapsProject</a> we reduced the bug reports by 40%, coincidence? Just add unit tests whenever you touch part of the old system, nurture them and they will grow on their own. Prove there is a better way and rewrite the old system when you get management support.--<a href="DonWells.html">DonWells</a>
<p><hr>
How can you generate useful <a href="UnitTests.html">UnitTests</a> for user interface code? Much of our code is visual C++ MFC based code. I can easily write unit tests for my own classes, for each function and module, but have real difficulty seeing how to apply this to the large classes the visual c++ generates. I can't test all of the functionality because it would take literally weeks to write the test code even if you could isolate the individual user interface classes, and it's all so dependent on user interaction anyway.
<p>Looking for any suggestions or comments. -- JohnBurton<a href="http://c2.com/cgi/wiki?edit=JohnBurton">?</a>
<p><em>A while back, I tried to start a discussion on this topic over in <a href="http://c2.com/cgi/wiki?GuiTesting">GuiTesting</a>. There's some useful stuff there, but I wish there were more. It seems to be a hard problem.</em>
<p>My thoughts are that you need to design your gui software with the thought
that's it needs to run automated tests. Make sure that the classes (functions, whatever) that handle the user interface have the minimum of code. Delegate <strong>all</strong> of the work that actually runs the application to modules that <em>are</em> testable. At least this minimizes the amount of code that can't be automatically unit tested and reduces the impact of any faults that exist in it. -- JohnBurton<a href="http://c2.com/cgi/wiki?edit=JohnBurton">?</a>
<p>Similarly, how do you <a href="http://c2.com/cgi/wiki?TestPrintedOutput">TestPrintedOutput</a>? -- <a href="http://c2.com/cgi/wiki?JoelShprentz">JoelShprentz</a> <em>Print to a file, compare the file with a standard one for equality.</em>
<p>Another way to <a href="http://c2.com/cgi/wiki?TestPrintedOutput">TestPrintedOutput</a> is unplug the printer from its port and plug in a computer emulating a printer.
When I worked for a telco, the operations guys used to periodically print out the internal tables from electronic exchanges, and capture the output on a laptop connected to the printer port.
<p>Now could we substitute the screen, mouse, and keyboard, to do GUI tests?
<PRE> -- <a href="http://c2.com/cgi/wiki?NickBishop">NickBishop</a>
</PRE><hr>
Some more <a href="http://c2.com/cgi/wiki?UnitTest">UnitTest</a> scenarios and questions are discussed in <a href="http://c2.com/cgi/wiki?UnitTestTrial">UnitTestTrial</a>
<hr>
We have noticed that unit testing leads to an interesting cultural change, wherby you begin to to start <a href="http://c2.com/cgi/wiki?ArguingThroughUnitTests">ArguingThroughUnitTests</a>. I witnessed this with some bemusement, and decided to write it up -- <a href="TimMackinnon.html">TimMackinnon</a>
<hr>
Two Questions:
<p>1) If <a href="http://c2.com/cgi/wiki?UnitTest">UnitTest</a> running time gets too long, how does one approach trimming and optimizing them such that no coverage is lost. My understanding of unit test writing is from <a href="http://c2.com/cgi/wiki?CodeComplete">CodeComplete</a>, which discusses writing the tests from both control and data points of view
<p>2) Do <a href="http://c2.com/cgi/wiki?UnitTest">UnitTest</a> cases get refactored as well as the production code?
<PRE> -- <a href="http://c2.com/cgi/wiki?RonGarcia">RonGarcia</a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -