问题
TDD is supposed to have 100% code coverage. Does this mean one is supposed to write tests for property getter and setters, and other methods that contain no real logic, such as dealing with external API functionality?
Example 1:
Below is one example method (which happens to also be the example in this other SO question which deals with how best to test it, if we are going to test it). This method doesn't do much. It's a facade of the System.ServiceProcess.ServiceController
functionality of stopping a service. Currently this code was not being written using TDD, but if it was, would it be something that one should test? There is very little logic here. The test in and of itself wouldn't be that helpful.
FYI: If you'd like to answer on how best to test it (IoC & Adapter Pattern vs. Detouring) please see this other SO question.
Public Function StopService(ByVal serviceName As String, ByVal timeoutMilliseconds As Double) As Boolean Implements IWindowsServicesService.StopService
Try
Dim service As New ServiceController(serviceName)
Dim timeout As TimeSpan = TimeSpan.FromMilliseconds(timeoutMilliseconds)
service.[Stop]()
If timeoutMilliseconds <= 0 Then
service.WaitForStatus(ServiceControllerStatus.Stopped)
Else
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout)
End If
Return service.Status = ServiceControllerStatus.Stopped
Catch ex As Win32Exception
Return False
Catch ex As TimeoutException
Return False
End Try
End Function
Example 2:
In case one argues that the code still has some logic, and therefore it needs to be tested when doing TDD, then what about the following code that has no logic:
Public Function GetProcess(ByVal serviceName As String) As Process
Dim managementObject As New ManagementObject(String.Format("Win32_service.Name='{0}'", serviceName))
Dim processID As Integer = CType(managementObject.GetPropertyValue("ProcessID"), Integer)
Dim process As Process = process.GetProcessById(processID)
Return process
End Function
回答1:
TDD is not supposed to have 100% code coverage. TDD tends to have very high code coverage, as compared to other methodologies. If you don't write a line of code without a failing test, if you follow that strictly, then yes, you'll get to 100% coverage. But most of us don't follow that strictly, and perfect code coverage is not the objective of TDD. High code coverage is a nice side effect of Test-Driven Development, but it is not the point.
Most of us don't test-drive simple getters and setters specifically as part of the TDD process. But we're not creating that field which needs the getter and setter until we have a need for it - where "need" is defined as a failing test. So the getter & setter will be tested as a matter of course, because they're created as needed by methods we are test driving.
Both of your examples have enough logic in them to be worthy of tests; I would test-drive both of them.
回答2:
In the interest of full disclosure: I'm no expert in TDD (I don't actually use it and never have), but I think I can argue from my ignorance for the TDD advocates in this case.
Imagine a situation where you have a simple "zero logic" property/function like example two. Suppose you implemented your own version of GetProcessById
which functions very slightly differently, but is interchangable with the Process
object. You decide not to write a test for this function, and say "Ahh, I'm just delegating it to the well-tested library, I can't possibly screw it up." There's your first mistake. "I can't possibly screw it up" is the single worst lie that programmers ever regularly tell themselves.
Suppose six months from now you realize you need to extend Process
with some extra stuff. You delegate all the right methods and override GetProcessById
. You now officially have to test this "zero logic" method. And that's the trouble. Polymorphism and many other features of programming languages (even ones that aren't strictly Object Oriented) lead to code which doesn't do exactly what you imagine it to do.
So, that being said, if you're following a strict TDD methodology, and you're striving for 100% test coverage, you'll want to test "zero-logic" methods, just like those two.
The only exception I can imagine is specific to .NET and that's automatically implemented properties, where there's no point in testing that the Getter and Setter work correctly, because even if they didn't there'd be nothing you could do about it. Test the object being wrapped in the property, not the property itself.
TDD folks, does that summarize it pretty well?
回答3:
Full disclosure: I don't use formal TDD and never have
Your code examples encapsulate a third-party complex API to get something done. Where will the bugs come from?
Most bugs will be caused by unexpected, possibly undocumented, behaviour from the API. It can be really hard to get those things to act right in every situation (Windows version / regional setting / network setup etc.) You can actually become a world-famous blogger just by documenting mistakes and misunderstandings people have made with the Win32 API.
- The most important tests are tests against the real API. You need some setup and teardown code to create processes or services.
- Mocking/IoC aren't very valuable. You're just proving that you are making particular API calls in a particular order. You need to prove that your code is achieving what you want, in all the situations it will encounter in the real world.
- I really think you can't do test-first development against mocks here. Imagine you find a bug in the third-party API (it happens). You'll need to work round the bug. You might even need to totally change your approach, maybe PInvoke to the Win32 API or some COM object. In that situation, mocked tests would just be a waste of time.
- First you'd have to code up a workaround that actually works against the real API.
- Then you'd have to edit the mocked tests to match the workaround.
- You couldn't edit the mocked tests first, because you have to try the workaround out to know whether it actually works.
My world is vertical-market desktop software. We have a library of routines like yours and we have realistic tests for them. Occasionally we find a bug on a particular Windows version / regional setting / whatever. Then we extend the tests to reproduce the bug and verify the fix, and make sure to rerun them on our set of test environments. Note to the reader: if your code only has to work on one server, maybe your world is different and you won't need to do this.
来源:https://stackoverflow.com/questions/4953032/does-one-still-write-tests-with-tdd-when-the-desired-code-has-little-to-no-logic