Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I haven't done much unit testing (never TDD'd), but I'm working on a project that I'd like at least the business layer to be unit-testable and there's a couple things I just can't seem to understand.
Say I have a feature that:
Prompts user for an Excel workbook filename
Loads the contents of the workbook into a grid
Displays that grid to the user on a form, which also takes a couple inputs from user
Displays a modal form with a progress bar that updates while the feature asynchronously...
Performs such or such operation (based on user inputs on the now closed form) and - roughly said, ends up importing the grid content into a database table.
I think I managed to properly separate business, data and presentation concerns here: the form contains only presentation-related code, data operations are method calls made on the DAL (Linq to SQL) and everything is coordinated in the business logic layer. Dependencies are injected in constructors; for example the form wants a DataTable, not an Excel workbook filename.
If I think of tests I could (or should) write, I ...simply can't think of any, other than trivial (useless?) ones that validate that a Foreach loop does the expected number of iterations, that a GetMilimeterDimensions function really does convert inches to milimeters (like, test that GetMilimeterDimensions(new SizeF(1f,1f)) does return a SizeF { Width = 25.4, Height = 25.4 }. Well reading this now it seems like the function's name should rather be something like ConvertInchToMilimeter and, well, this feels like a function that belongs as a static method to some BusinessMath class. Bad example I guess.
Point is, all these functions and methods I'd want to test, are all private and ultimately called by the class' COM-visible Execute() method. Does that mean I must make them public just for testing? Or, what, embed the behavior of my functionality into some FunctionalityImplementation class that does expose its methods, and have my functionality call these methods instead? Feels like overkill...
Then there's the DAL calls; I'd need to implement some repository pattern in order to mock CRUD operations and be able to write tests that validate whether the expected number of records get inserted... but that's beyond the business layer testability I guess.
Nevertheless, seems like a lot of work just to get a bunch of green dots in some VS plugin. I realize that once the test is written, code changes that break a test make you thankful the test was written in the first place, but I think I'm completely missing the point of unit testing and that tests I would write would be meaningless if at all useful; please help me out here, the more I think about it the more it seems to me unit tests are just additional work that imposes its design patterns.
Don't get me wrong (with the question's title I guess), I do see the benefits of TDD, I've read ASP.NET MVC books written by unit test enthusiasts, but I just can't seem to wrap my head around how to apply these principles to a simple functionality, let alone to a whole COM-visible library project...
Unit testing isn't a burden; it saves a lot of time, prevents errors, and facilitates refactoring that keeps code maintainable and malleable.
But you might not need unit tests for this project.
The most urgent unit tests would ensure that your business logic does what you think it does. That's really useful where the business logic is complicated, has lots of moving parts, and is likely to grow more complex over time:
Person *p = ...sample person....;
LoanRequest loan(p, $1,000,000);
Assert(loan.CanBeApproved(bankPolicy,region,market,term),true);
But it's not essential if the underlying logic is simple and evidently correct
Price=Total+Shipping;
Similarly, if you're writing a quick widget for immediate short-term use, long-term maintenance isn't your first concern and the role of tests as documentation for future collaborators is probably irrelevant. If you're building a product, though, you'll want those tests.
In general, unit tests should primarily be concerned with public behavior. But occasionally you may find it much easier to verify intermediate results that are normally private. Making a method public, or providing a special hook for testing, can be a reasonable price to pay for confidence that the software does what you think, and will continue to do what you think even after other people start changing it.
Related
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 3 years ago.
Improve this question
I've been applying TDD to some new projects to get the hang of things, and I understand the basic flow: Write tests that fail, write code to pass tests, refactor if needed, repeat.
To keep the tests fast and decoupled, I abstract out things like network requests and file I/O. These are usually abstracted into interfaces which get passed through using dependency injection.
Usually development is very smooth until the end where I realize I need to implement these abstract interfaces. The whole point of abstracting them was to make it easily testable, but following TDD I would need to write a test before writing the implementation code, correct?
For example, I was looking at the tdd-tetris-tutorial https://github.com/luontola/tdd-tetris-tutorial/tree/tutorial/src/test/java/tetris. If I wanted to add the ability to play with a keyboard, I would abstract away basic controls into methods inside a Controller class, like "rotateBlock", "moveLeft", etc. that could be tested.
But at the end I would need to add some logic to detect keystrokes from the keyboard when implementing a controller class. How would one write a test to implement that?
Perhaps some things just can't be tested, and reaching 100% code coverage is impossible for some cases?
Perhaps some things just can't be tested, and reaching 100% code coverage is impossible for some cases?
I use a slightly different spelling: not all things can be tested at the same level of cost effectiveness.
The "trick", so to speak, is to divide your code into two categoies: code that is easy to test, and code that is so obvious that you don't need to test it -- or not as often.
The nice thing about simple adapters is that (once you've got them working at all) they don't generally need to change very much. All of the logic lives somewhere else and that somewhere else is easy to test.
Consider, for example, reading bytes from a file. That kind of interface looks sort of like a function, that accepts a filename as an argument and either returns an array of bytes, or some sort of exception. Implementing that is a straight forward exercise in most languages, and the code is so text book familiar that it falls clearly into the category of "so simple there are obviously no deficiencies".
Because the code is simple and stable, you don't need to test it at anywhere near the frequency that you test code you regularly refactor. Thus, the cost benefit analysis supports the conclusion that you can delegate your occasional tests of this code to more expensive techniques.
100% statement coverage was never the goal of TDD (although it is really easy to understand how you -- and a small zillion other people -- reached that conclusion). It was primarily about deferring detailed design. So to some degree code that starts simple and changes infrequently was "out of bounds" from the get go.
You can't test everything with TDD unit tests. But if you also have integration tests, you can test those I/O interfaces. You can produce integration tests using TDD.
In practice, some things are impractical to automatically test. Error handling of some rare error conditions or race hazards are the hardest.
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 9 years ago.
Improve this question
I have a method CreateTask(UserId).
For this method, is it enough to check UserId against null or empty and an invalid value?
Or should I check whether Task is created for a specific UserId?
And should I also check number of tasks created and their date and time?
I don't think there's enough information here to answer this. But ti address some of your points:
For this method, Is that enough to check UserId null or empty and invalid Id ?
The method itself can internally do that, but that's not part of testing. That's just a method at runtime doing some error checking. This is often referred to as "defensive programming."
Or Should I check whether Task is created for the specif UserId.?
This is where it gets cloudy. And this is where you would want to step back for a moment and look at the bigger picture. Make sure you're not tightly coupling your unit tests with your implementation logic. The tests should validate the business logic, unaware of the implementation.
It's highly likely that "creating a task" isn't business logic, but rather simply an implementation detail. What you should be testing is that when Step A is performed, Result B is observed. How the system goes about producing Result B is essentially what's being tested, but not directly or explicitly.
A big reason for keeping your unit tests high-level like this is because if the implementation details change then you don't want to have to change your tests with them. That drastically reduces the value of those tests because it not only adds more work to any change but it eliminates the tests as the validation point of those change, since the tests themselves also change. The tests should be fairly simple and static, acting as a set of rules used to validate the code. If the tests are complex and often changing, they lose that level of confidence needed to validate the code.
You don't have to test every method. You should test every observable business action that the system performs. Methods which perform those actions get tested as a result of this. Methods which don't perform those actions are then questionable as to whether or not you need them in the first place. A code coverage tool is great for determining this.
For example, let's say you have MethodA() which doesn't get used by any of the tests. No test calls it directly, because it's just an implementation detail and the tests don't need to know about it. (In this case it might even make sense for the method to be private or in some other way obscured from the external calling code.) This leaves you with two options:
The tests are incomplete, because MethodA() is needed by a business process which isn't being tested. Add tests for that business process.
The tests are complete, and MethodA() isn't actually needed by the system. Remove it.
If your tests blindly test every method regardless of the bigger picture of the business logic, you'd never be able to determine when something isn't needed by the system. And deprecating code which is no longer needed is a huge part of keeping a simple and maintainable codebase.
1) Keep your methods short and simple, so unit testing will be easy (btw. one of reasons that TDD encourages good design)
2) Check all boundary conditions (invalid input, trivial input etc.) (btw. one of ways to make TDD easy)
3) Check all possible scenarios to achieve high coverage (all possible execution flows through your method with simplest input to achieve this) (btw. one of reasons that TDD works)
4) Check few (maybe one) typical scenarios with real data that demonstrates typical usage of the method
And as you've probably noticed - consider using TDD so you won't have to worry about the issue of "testing an existing method" :)
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
As far as I know from eXtreme Programming and unit testing, tests must be done by another developer before another one develop the tested method (or from the same developers but test must be written before the method implementation).
Ok, seems good, we just need to test if a method has a good behavior when I give it some parameters.
But the difference between theory and practice is that in theory there isn't but in practice there is...
The first time I've tried to test, I've found it difficult in some cases due to relations between objects. I discovered mocking practice and I found it very useful but some concepts make me doubt.
First, mocking implicit says : "You know how the method runs because you must to know what other objects it needs...". Well, in theory that's my friend bob which writes the test and he just knows that the method must return true when I give it "john" string... It's me who code this method using a dao to access a database instead of using an hashtable in memory...
How my poor friend Bob will write its test ? He will anticipate my work...
Ok, seems to not be the pure theory but no matter. But if I look at the documentation of a lot of mock frameworks, they allow me to test how many times a method is called and in what order ! ouch...
But if my friend Bob must test this method like that to ensure good use of dependencies, the method must be written before the test, isn't it ?
Hum... Help my friend Bob...
When do we stop to use mock mechanism (order verification and so on) ?
When mock mechanisms are useful ?
Theory, practice and mock : what is the best balance ?
What you seem to be missing from your description is the concept of separating contract from implementation. In C# and Java, we have interfaces. In C++, a class composed only of pure virtual functions can fill this role. These aren't really necessary, but helpful in establishing the logical separation. So instead of the confusion you seem to be experiencing, practice should go more like: Bob writes the unit tests for one particular class/unit of functionality. In doing so, he defines one or more interfaces (contracts) for other classes/units that will be needed to support this one. Instead of needing to write those right now, he fills them in with mock objects to provide for the indirect input and output required by his test and the system under test. Thus the output of a set of unit tests is not just the tests to drive development of a single unit, but that plus the contracts required to be implemented by other code to support the unit currently under development.
I'm not sure if I understand your question.
Use mocks to verify collaboration between objects. For example, suppose you have a Login() method that takes a username and password. Now suppose you want this method to Log failed log in attempts. In your unit test you would create a mock Logger object and set an expectation on it that it will be called. Then you would dependency inject it into your login class and call your Login method with a bad username and password to trigger a log message.
The other tool you have in your unit testing tool bag is stubs. Use stubs when you're not testing collaborations but to fake dependencies in order to get your class under test to run.
Roy Osherove, the author of the The Art of Unit Testing, has a good video on mocks: TDD - Understanding Mock Objects
Also I recommend going to his website http://artofunittesting.com/ and watching the free videos on the right side under the heading "Unit Testing Videos".
When you are writing a unit test you are testing the outcome and/or behavior of the class under test against an expected outcome and/or behavior.
Expectations can change over the time that you develop the class - new requirements can come in that change how the class should behave or what the outcome of calling a particular method is. It is never set in stone and unit tests and the class under tests evolve together.
Initially you might start out with just a few basic tests on a very granular level, which then evolve into more and more tests, some of which might be very particular to the actual implementation of your class under test (at least as far as the observable behavior of that class is concerned).
To some degree you can write out many of your tests against a raw stub of your class under test, that produces the expected behavior but mostly has no implementation yet. Then you can refactor/develop the class "for real".
In my opinion it is a pipe dream though to write all your tests in the beginning and then fully develop the class - in my experience both tests and class under tests evolve together. Both can be written by the same developer too.
Then again I am certainly not a TDD purist, just trying to get the most out of unit tests in a pragmatic way.
I'm not sure what exactly is the problem. So I may not accurately answer the question, but I'll give it a try.
Suppose you are writing system A, where A need to get data (let's say a String for simplicity) from a provider, and then A inverse that String and send it to another system C.
B and C are provided to you, and they actually interfaces, the implementations in real life may be BImpl, and CImpl.
for the purposes of your work, you know, that you need to call the readData() from system B, and sendData(String) from system C. Your friend Bob should know that as well, you shouldn't send the data before you get it. Also if you get "abcd" you should send "dcba"
looks like both you and Bob should know this, he writes the tests, and you write the code... where is the problems in that?
of course real life is more complicated, but you should still be able to model it with simple interactions that you unit test.
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'm fairly new to the unit testing world, and I just decided to add test coverage for my existing app this week.
This is a huge task, mostly because of the number of classes to test but also because writing tests is all new to me.
I've already written tests for a bunch of classes, but now I'm wondering if I'm doing it right.
When I'm writing tests for a method, I have the feeling of rewriting a second time what I already wrote in the method itself.
My tests just seems so tightly bound to the method (testing all codepath, expecting some inner methods to be called a number of times, with certain arguments), that it seems that if I ever refactor the method, the tests will fail even if the final behavior of the method did not change.
This is just a feeling, and as said earlier, I have no experience of testing. If some more experienced testers out there could give me advices on how to write great tests for an existing app, that would be greatly appreciated.
Edit : I would love to thank Stack Overflow, I had great inputs in less that 15 minutes that answered more of the hours of online reading I just did.
My tests just seems so tightly bound to the method (testing all codepath, expecting some inner methods to be called a number of times, with certain arguments), that it seems that if I ever refactor the method, the tests will fail even if the final behavior of the method did not change.
I think you are doing it wrong.
A unit test should:
test one method
provide some specific arguments to that method
test that the result is as expected
It should not look inside the method to see what it is doing, so changing the internals should not cause the test to fail. You should not directly test that private methods are being called. If you are interested in finding out whether your private code is being tested then use a code coverage tool. But don't get obsessed by this: 100% coverage is not a requirement.
If your method calls public methods in other classes, and these calls are guaranteed by your interface, then you can test that these calls are being made by using a mocking framework.
You should not use the method itself (or any of the internal code it uses) to generate the expected result dynamically. The expected result should be hard-coded into your test case so that it does not change when the implementation changes. Here's a simplified example of what a unit test should do:
testAdd()
{
int x = 5;
int y = -2;
int expectedResult = 3;
Calculator calculator = new Calculator();
int actualResult = calculator.Add(x, y);
Assert.AreEqual(expectedResult, actualResult);
}
Note that how the result is calculated is not checked - only that the result is correct. Keep adding more and more simple test cases like the above until you have have covered as many scenarios as possible. Use your code coverage tool to see if you have missed any interesting paths.
For unit testing, I found both Test Driven (tests first, code second) and code first, test second to be extremely useful.
Instead of writing code, then writing test. Write code then look at what you THINK the code should be doing. Think about all the intended uses of it and then write a test for each. I find writing tests to be faster but more involved than the coding itself. The tests should test the intention. Also thinking about the intentions you wind up finding corner cases in the test writing phase. And of course while writing tests you might find one of the few uses causes a bug (something I often find, and I am very glad this bug did not corrupt data and go unchecked).
Yet testing is almost like coding twice. In fact I had applications where there was more test code (quantity) than application code. One example was a very complex state machine. I had to make sure that after adding more logic to it, the entire thing always worked on all previous use cases. And since those cases were quite hard to follow by looking at the code, I wound up having such a good test suite for this machine that I was confident that it would not break even after making changes, and the tests saved my ass a few times. And as users or testers were finding bugs with the flow or corner cases unaccounted for, guess what, added to tests and never happened again. This really gave users confidence in my work in addition to making the whole thing super stable. And when it had to be re-written for performance reasons, guess what, it worked as expected on all inputs thanks to the tests.
All the simple examples like function square(number) is great and all, and are probably bad candidates to spend lots of time testing. The ones that do important business logic, thats where the testing is important. Test the requirements. Don't just test the plumbing. If the requirements change then guess what, the tests must too.
Testing should not be literally testing that function foo invoked function bar 3 times. That is wrong. Check if the result and side-effects are correct, not the inner mechanics.
It's worth noting that retro-fitting unit tests into existing code is far more difficult than driving the creation of that code with tests in the first place. That's one of the big questions in dealing with legacy applications... how to unit test? This has been asked many times before (so you may be closed as a dupe question), and people usually end up here:
Moving existing code to Test Driven Development
I second the accepted answer's book recommendation, but beyond that there's more information linked in the answers there.
Don't write tests to get full coverage of your code. Write tests that guarantee your requirements. You may discover codepaths that are unnecessary. Conversely, if they are necessary, they are there to fulfill some kind of requirement; find it what it is and test the requirement (not the path).
Keep your tests small: one test per requirement.
Later, when you need to make a change (or write new code), try writing one test first. Just one. Then you'll have taken the first step in test-driven development.
Unit testing is about the output you get from a function/method/application.
It does not matter at all how the result is produced, it just matters that it is correct.
Therefore, your approach of counting calls to inner methods and such is wrong.
What I tend to do is sit down and write what a method should return given certain input values or a certain environment, then write a test which compares the actual value returned with what I came up with.
Try writing a Unit Test before writing the method it is going to test.
That will definitely force you to think a little differently about how things are being done. You'll have no idea how the method is going to work, just what it is supposed to do.
You should always be testing the results of the method, not how the method gets those results.
tests are supposed to improve maintainability. If you change a method and a test breaks that can be a good thing. On the other hand, if you look at your method as a black box then it shouldn't matter what is inside the method. The fact is you need to mock things for some tests, and in those cases you really can't treat the method as a black box. The only thing you can do is to write an integration test -- you load up a fully instantiated instance of the service under test and have it do its thing like it would running in your app. Then you can treat it as a black box.
When I'm writing tests for a method, I have the feeling of rewriting a second time what I
already wrote in the method itself.
My tests just seems so tightly bound to the method (testing all codepath, expecting some
inner methods to be called a number of times, with certain arguments), that it seems that
if I ever refactor the method, the tests will fail even if the final behavior of the
method did not change.
This is because you are writing your tests after you wrote your code. If you did it the other way around (wrote the tests first) it wouldnt feel this way.
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 6 years ago.
Improve this question
Let's say I'm starting a new project, quality is a top priority.
I plan on doing extensive unit testing, what's important to keep in mind when I'm working on the architecture to ease and empower further unit testing?
edit : I read an article some times ago (I can't find it now) talking about how decoupling instantiation code from classes behaviors could be be helpful when unit testing. That's the kind of design tips I'm seeking here.
Ease of testing comes through being able to replace as many of the dependencies your method has with test code (mocks, fakes, etc.) The currently recommended way to accomplish this is through dependency inversion, aka the Hollywood Principle: "Don't call us, we'll call you." In other words your code should "ask for things, don't look for things."
Once you start thinking this way you'll find code can easily have dependencies on many things. Not only do you have dependencies on other objects, but databases, files, environment variables, OS APIs, globals, singletons, etc. By adhering to a good architecture, you minimize most of these dependencies by providing them via the appropriate layers. So when it comes time to test, you don't need a working database full of test data, you can simply replace the data object with a mock data object.
This also means you have to carefully sort out your object construction from your object execution. The "new" statement placed in a constructor generates a dependency that is very hard to replace with a test mock. It's better to pass those dependencies in via constructor arguments.
Also, keep the Law of Demeter in mind. Don't dig more than one layer deep into an object, or else you create hidden dependencies. Calling Flintstones.Wilma.addChild(pebbles); means what you thought was a dependence on "Flintstones" really is a dependence on both "Flintstones" and "Wilma".
Make sure that your code is testable by making it highly cohesive, lowly decoupled. And make sure you know how to use mocking tools to mock out the dependencies during unit tests.
I recommend you to get familiar with the SOLID principle, so that you can write a more testable code.
You might also want to check out these two SO questions:
Unit Test Adoption
What Should Be A Unit
Some random thoughts:
Define your interfaces: decouple the functional modules from each other, and decide how they will communicate with each other. The interface is the “contract” between the developers of different modules. Then, if your tests operate on the interfaces, you're ensuring that the teams can treat each other's modules as black boxes, and therefore work independently.
Build and test at least the basic functionality of the UI first. Once your project can “talk” to you, it can tell you what's working and what's not ... but only if it's not lying to you. (Bonus: if your developers have no choice but to use the UI, you'll quickly identify any shortcomings in ease-of-use, work flow, etc.)
Test at the lowest practical level: the more confident you are that the little pieces work, the easier it will be to combine them into a working whole.
Write at least one test for each feature, based on the specifications, before you start coding. After all, the features are the reason your customers will buy your product. Be sure it's designed to do what it's supposed to do!
Don't be satisfied when it does what it's supposed to do; ensure it doesn't do what it's not supposed to do! Feed it bad data, use it in an illogical way, disconnect the network cable during data transfer, run it alongside conflicting applications. Your customers will.
Good luck!
Your tests will only ever be as good as your requirements. They can be requirements that you come up with up front all at once, they can be requirements that you come up with one at a time as you add features, or they can be requirements that you come up with after you ship it and people start reporting a boat load of bugs, but you can't write a good test if no one can or will document exactly what the thing is supposed to do.