开发者

General idea of unit testing

This question might be slightly vague but here goes. I've just started unit testing and I seem to be struggling with the basic notion.

I'm testing a function that checks if a record exists in the database. If not, it adds the new record and returns its ID. So the function is simple to write. And the o开发者_Go百科nly way I can think to test it is by using the mocking framework to check that the right properties/methods were called the right number of times.

The part I'm struggling with is that everything I have ever read talks about writing tests first and then the function. But I feel like it'll only work if I write the function first, and then write tests that reflect the inner workings of the functions.

Is there really a golden rule for this?

And how much should I be testing basic transactional logic anyway?


Maybe if you wanna develop at this level you can write the method's contract first and than the test depending on the contract. It is important that your method behaves like defined in the contract, because this is what other developers will expect. Especially the edge cases (exceptions and so on) should be tested.

If you are going to change your contract while developing the method, well, than that's not good. Because than you have not planed your software good and as well you can rewrite your tests =)

Testing is important because when you do code changes, you will later be able to detect the errors easier with the saved tests, when you mashed something up, by trying to develop something new.


The part I'm struggling with is that everywhere i have ever read talks about writing tests first and then the function. But i feel like it'll only work if i write the function first then write tests that reflect the inner workings of the functions.

It sounds like you are suffering from the common chicken/egg problem with test-driven development (TDD). You don't know what you want to test until you have code, and you believe you can't do TDD unless you write tests before you code.

This is really a case of Designer's Block (tm). Just like writer's block, it is often good to work it out by coding - even if you throw all that code away.

Hack up a prototype, and then pretend it doesn't exist. (do not ship it :) This prototype should explore the concepts you weren't familiar with, or didn't have enough information to start designing. It should get you familiar with the problem so that you can start designing.

After you have a proof of concept, code review the heck out of it. In your review, determine what you want the public interface to look like, what architectural patterns would best suit the program, and which dependencies should be isolated from each other (and mocked out in your tests). Take notes, or submit requirements in your project planning software/work items in your project tracking software.

If you have troubles identifying these things in your review, you should try to recruit other programmers (and possibly designers/people who identify your business requirements) to help you through it. A code mentor may be a good idea.

From that review, you should be able to start coding up your tests. Or you could begin writing a technical spec - this advice applies equally well to both.

(if you are working on a team, gathering requirements and getting user feedback/performing UATs is also required; but that might be someone else's job)

Edit

Keep in mind that this is just one approach for dealing with this problem. Another is to simply relax any puritan-like ideals on how TDD should work, and simply develop your tests in parallel with your code. Check them in at the same time.

It is also perfectly fine to do unit testing without TDD. Unit tests confer more benefits than just encoding your design and requirements. They also are a huge help when you add new features or fix bugs (regression testing), or when you port your code.


There are good reasons for writing tests first:

  1. You make sure that your test actually fails. If you write your implementation first, and then the test, the test will pass, but you will not know whether it really works. There could be an error in the test! If you write the test first, you can run it and make sure that it fails.
  2. If you only write code that is necessary to pass the tests you have, you will get a very high code coverage.
  3. If you write tests first, including all the mocks and fakes needed, you get a better understanding of the requirements. When mocking a certain API, you may find that there is some extra information you need to make an API-call or something like that.
  4. Motivation. If you have code already written, it is too easy to just go Naaah, I don't need to test all of it. Wrong. If you go the other way around, this is still possible, but it the inhibition threshold is higher.

All in all, it can feel hard, but the reward is well worth it.


As far as I know, I'd say that you should always keep in mind how you will test the function, but code the function itself first. This will allow you to locate critical parts and eventual bugs that could occur. You could also test the outputs/inputs of your function, and make sure that they correspond to the desired results - Black Box testing works well with this pre-coding unit testing.

I've also been struggling with this idea of writting unit tests before coding your actual method. Please keep in mind I'm only a student and this is just my opinion.

Hope it helps, hope I'm right :)


And how much should i be testing basic transactional logic anyway?

It's my experience the more tests you write, the happier you'll be.

Testing the basic transactional logic will give you experience with your classes and how they interoperate, and give you an idea of their speed, and even how the basic transactional logic really works.

It will help you become better at writing test cases, because practice makes perfect.

And later on, who knows, it will help you detect a bug when you upgrade your database, or change databases entirely.


I'll specifically try to answer your question about testing basic transaction logic. Most of the time I write unit tests for the units higher in the hierarchy. For example, in a basic model-view-controller setup my unit tests are testing the controllers, not the underlying DAL. Why? Because I assume that when a controller passes the tests the layers beneath the controller will also work fine.

There's an exception though, for shared libs. Libraries that are shared over many projects will get their own unit tests, for example to ensure stability of the API.

Also, look at your unit tests as another application in your project. Make sure you don't c/p code in tests, don't throw a bunch of test fixtures together but take your time to design a nice structure that's extensible. It will save you a lot of time in the feature.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜