views:

168

answers:

7

How to verify a result of program that is hard to grasp? For example a year ago I had to wrote a B tree as schoolwork and I really struggled with that mainly because I was clueless how to verify proper result. What strategies do you use in such scenarios? Visualization? Robust input-->result sets of testing data? What do you do when is hard to get such data because the only way how to get them is your proper working program? I will really appreciate any edit of my grammar because I suck at English :) Thanks

EDIT: I think that my question was misunderstood. There was not problem with understanding how is B tree working. That is trivial. But writing robust tests for validating its proper functionality is not so trivial! I think that this school problem is similar to many practical REAL word scenarios and test cases. And sometimes understanding the domain is quite different from delivering working and correct program...

EDIT2: And yes, with B tree it is possible to validate proper behavior with pen and paper. But this is really dirty and not funny. This is not working well with problems that requires huge amount of data for their validation...

A: 

Consult with an expert on the subject.

I know if I have a convoluted procedure I'm trying to fix, I have no idea what the output should be after my changes, so I need to consult a fellow developer with more knowledge of the business need, and they are able to verify what I've done is correct.

glasnt
Like the experts on Stack Overflow?
emddudley
@emddudley : If it's for a B-tree, then sure. However, if it's for a business user aspect, then the expert could be a power user, another developer, a business analyst etc. I wouldn't ask someone on the internet a question about enterprise-specific processes.
glasnt
+2  A: 

If you do not grasp the problem at hand, how can you develop a solution to it? My suggestion would be to understand the domain enough to be able to work out the problem on paper and ensure that your program matches.

Brian
As Brian said, you can't verify the result or even apply the correct solution unless you understand the problem.
Chris Lively
I think you are wrong. You can perfectly understand the domain but any nontrivial software is prone to bug. And sometimes is REALLY hard to realize that. It is quite different when you have a bad validation on customer email and when you have a big input and complex algorihtms that transform it to complex output. You can really well known the domain and what is doing under the hood but YOU_NEED_TO_VERIFY your program. And that is sometimes TRICKY
Bystrik Jurina
It is often tricky. Testing is often a more time consuming process than actually solving the problem in the first place. Validating the correctness of your algorithm takes hard work and often I personally go to pen and paper. Call me old fashioned but stepping through a Business use case and solving it as it would be solved before the program I created is a surefire way to verify your algorithm. If you need to consult the business stakeholder and get test input/expected results so be it.
Brian
A: 

I would focus on constructing test cases that exercise the functionality of your B-tree algorithm. I haven't looked at it for years, but I'm fairly sure you'll be able to find a documented sequence of steps to insert a set of values in a specific order, then validate that the leaf nodes are as they should be. If you construct your testing along these lines, you should be able to prove your implementation is correct.

Dave
There is not any problem with B tree. That is history. But it comes today into my mind when I evaluate some testing strategies in general.
Bystrik Jurina
A: 

The key is to know there is a balance between testing something to death and doing tests that adequately cover what should be covered. Edge cases, e.g null inputs or checking inputs are numeric by testing an alphabet character or a punctuation character, are likely most of the tests you'd need. To complement this there may be one or two common cases to handle to show the program can handle a non-edge case as well. To cover all valid input in most programs is overkill and would result in an overwhelmingly large amount of tests.

JB King
A: 

I think the answer to the question you're asking boils down to designing for testability. Often you get a testable design for free when you test-drive the development of the solution. But let's face it, when you're implementing a highly mathematical algorithm, this just doesn't fall out.

To make sure you have a testable design, you need to understand what a seam is. Then you need to know a few rules of thumb, such as avoiding statics, using polymorphism, and properly decomposing problems and separating concerns.

Watch "The Clean Code Talks -- Unit Testing" by Misko Hevery, I think it will help you wrap your head around it.

cwash
+2  A: 

I'm not sure these answers really capture the problem at hand. A B-tree's input and output aren't any different from those of any other dictionary---but the algorithm performs better, if it's implemented correctly. It's only really got two functions to test (add, and find) so theoretically, "black-box" testing of this single component should be fine. Designing for testability isn't the issue, since no matter how you do it the whole algorithm will be one component.

So the question is: when you have to implement subtle algorithms, the kinds with complicated output that you can't always understand in your head so well, how do you test them? I think there are three different strategies you can use:

  1. Black-box test basic functionality. For the B-tree case, this is things like cwash suggested, and also, things like making sure that when you add an item, you can then find it, etc.

  2. Test certain invariants that your algorithm should maintain (the B-tree should be balanced, values within nodes should be sorted, etc.)

  3. A few, small "pencil-and-paper" tests may be necessary -- work the algorithm out by hand and check that it matches what your code does. But the big-data tests can all be of type 2. These can also be brittle, so unless you need to be really sure about your algorithm, you may want to avoid them.

Jacob B
Good answer. I've taken this approach before when solving pretty complicated problems. The question to me is a little academic in that I don't find myself implementing binary trees on my own very often. But I have spiked on various unfamiliar APIs and using pencil and paper tests is the only way to start. Make sure you understand the nuts and bolts of the algorithm by writing a test. TestNG's Dataprovider works well for things like this. Here is an example where I've done just this: http://is.gd/19LH0
cwash
Your point about "one component algorithm" is great. It would be great to have options for mocking any method...Or maybe inheritance is the answer for such problem. But it seems strange to have for every tested method different inherited class which overrides desired methods(really crazy "mocking").
Bystrik Jurina
I think the answer to testing component internals--which you do have to do, sometimes--is that you have to have some "white-box" tests, that know about what's inside. In C++, you can do this with friend tests, for instance. These can be brittle, and you should probably avoid them if possible, but if they're necessary, they're necessary.
Jacob B
A: 

Try looking at it from a requirements point of view, rather than an implementation point of view. Before you write code, you must understand exactly what you want it to do.

Testing and requirements should be a matching pair. If you're having trouble defining tests, maybe it's because the requirements are not well-defined. That in turn implies that you may have bugs that aren't so much implementation bugs, but "lack of clear requirements" bugs. The code writer in that case would be working to a mental list of requirements that he/she thinks is requirements, but can't be sure, and they're not written down for independent understanding and verification.

I've struggled with software where the requirements weren't clear, because the customer couldn't even tell us what they wanted. But when we delivered to them, they sure could tell us then what they didn't like about it! A big part of software engineering is getting the requirements right before the coding begins. This is true on the high-level (overall product, with requirement input from customer) and also the smaller level (modules, individual functions, where requirements are internally defined by software team or individuals). It is still true to some degree I think for iterative development, although the high-level requirements are more fluid.

Craig McQueen