Why use JUnit for testing?

后端 未结 11 1451
忘掉有多难
忘掉有多难 2020-12-12 09:59

Maybe my question is a newbie one, but I can not really understand the circumstances under which I would use junit?

Whether I write simple applications or larger one

相关标签:
11条回答
  • 2020-12-12 10:26

    Unit tests ensure that code works as intended. They are also very helpful to ensure that the code still works as intended in case you have to change it later to build new functionalities to fix a bug. Having a high test coverage of your code allows you to continue developing features without having to perform lots of manual tests.

    Your manual approach by System.out is good but not the best one.This is one time testing that you perform. In real world, requirements keep on changing and most of the time you make a lot of modificaiotns to existing functions and classes. So… not every time you test the already written piece of code.

    there are also some more advanced features are in JUnit like like

    Assert statements

    JUnit provides methods to test for certain conditions, these methods typically start with asserts and allow you to specify the error message, the expected and the actual result

    Some of these methods are

    1. fail([message]) - Lets the test fail. Might be used to check that a certain part of the code is not reached. Or to have failing test before the test code is implemented.
    2. assertTrue(true) / assertTrue(false) - Will always be true / false. Can be used to predefine a test result, if the test is not yet implemented.
    3. assertTrue([message,] condition) - Checks that the boolean condition is true.
    4. assertEquals([message,] expected, actual) - Tests whether two values are equal (according to the equals method if implemented, otherwise using == reference comparison). Note: For arrays, it is the reference that is checked, and not the contents, use assertArrayEquals([message,] expected, actual) for that.
    5. assertEquals([message,] expected, actual, delta) - Tests whether two float or double values are in a certain distance from each other, controlled by the delta value.
    6. assertNull([message,] object) - Checks that the object is null

    and so on. See the full Javadoc for all examples here.

    Suites

    With Test suites, you can in a sense combine multiple test classes into a single unit so you can execute them all at once. A simple example, combining the test classes MyClassTest and MySecondClassTest into one Suite called AllTests:

    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    import org.junit.runners.Suite.SuiteClasses;
    
    @RunWith(Suite.class)
    @SuiteClasses({ MyClassTest.class, MySecondClassTest.class })
    public class AllTests { } 
    
    0 讨论(0)
  • 2020-12-12 10:27

    We write tests to verify the correctness of a program's behaviour.

    Verifying the correctness of a program's behaviour by inspecting the content of output statements using your eyes is a manual, or more specifically, a visual process.

    You could argue that

    visual inspection works, I check that the code does what it's meant to do, for these scenarios and once I can see it's correct we're good to go.

    Now first up, it's great to that you are interested in whether or not the code works correctly. That's a good thing. You're ahead of the curve! Sadly, there are problems with this as an approach.

    The first problem with visual inspection is that you're a bad welding accident away from never being able to check your code's correctness again.

    The second problem is that the pair of eyes used is tightly coupled with the brain of the owner of the eyes. If the author of the code also owns the eyes used in the visual inspection process, the process of verifying correctness has a dependency on the knowledge about the program internalised in the visual inspector's brain.

    It is difficult for a new pair of eyes to come in and verify the correctness of the code simply because they are not partnered up with brain of the original coder. The owner of the second pair of eyes will have to converse with original author of the code in order to fully understand the code in question. Conversation as a means of sharing knowledge is notoriously unreliable. A point which is moot if the Original Coder is unavailable to the new pair eyes. In that instance the new pair of eyes has to read the original code.

    Reading other people's code that is not covered by unit tests is more difficult than reading code that has associated unit tests. At best reading other peoples code is tricky work, at its worst this is the most turgid task in software engineering. There's a reason that employers, when advertising job vacancies, stress that a project is a greenfield (or brand new) one. Writing code from scratch is easier than modifying existing code and thereby makes the advertised job appear more attractive to potential employees.

    With unit testing we divide code up into its component parts. For each component we then set out our stall stating how the program should behave. Each unit test tells a story of how that part of the program should act in a specific scenario. Each unit test is like a clause in a contract that describes what should happen from the client code's point of view.

    This then means that a new pair of eyes has two strands of live and accurate documentation on the code in question.

    First they have the code itself, the implementation, how the code was done; second they have all of the knowledge that the original coder described in a set of formal statements that tell the story of how this code is supposed to behave.

    Unit tests capture and formally describe the knowledge that the original author possessed when they implemented the class. They provide a description of how that class behaves when used by a client.

    You are correct to question the usefulness of doing this because it is possible to write unit tests that are useless, do not cover all of the code in question, become stale or out of date and so on. How do we ensure that unit tests not only mimics but improves upon the process of a knowledgeable, conscientious author visually inspecting their code's output statements at runtime? Write the unit test first then write the code to make that test pass. When you are finished, let the computers run the tests, they're fast they are great at doing repetitive tasks they are ideally suited to the job.

    Ensure test quality by reviewing them each time you touch off the code they test and run the tests for each build. If a test fails, fix it immediately.

    We automate the process of running tests so that they are run each time we do a build of the project. We also automate the generation of code coverage reports that details what percentage of code that is covered and exercised by tests. We strive for high percentages. Some companies will prevent code changes from being checked in to source code control if they do not have sufficient unit tests written to describe any changes in behaviour to the code. Typically a second pair of eyes will review code changes in conjunction with the author of the changes. The reviewer will go through the changes ensure that the changes understandable and sufficiently covered by tests. So the review process is manual, but when the tests (unit and integration tests and possibly user acceptance tests) pass this manual review process the become part of the automatic build process. These are run each time a change is checked in. A continuous-integration server carries out this task as part of the build process.

    Tests that are automatically run, maintain the integrity of the code's behaviour and help to prevent future changes to the code base from breaking the code.

    Finally, providing tests allows you to aggressively re-factor code because you can make big code improvements safe in the knowledge that your changes do not break existing tests.

    There is a caveat to Test Driven Development and that is that you have to write code with an eye to making it testable. This involves coding to interfaces and using techniques such as Dependency Injection to instantiate collaborating objects. Check out the work of Kent Beck who describes TDD very well. Look up coding to interfaces and study design-patterns

    0 讨论(0)
  • 2020-12-12 10:27

    I have slightly different perspective of why JUnit is needed.

    You can actually write all test cases yourself but it's cumbersome. Here are the problems:

    1. Instead of System.out we can add if(value1.equals(value2)) and return 0 or -1 or error message. In this case, we need a "main" test class which runs all these methods and checks results and maintains which test cases failed and which are passed.

    2. If you want to add some more tests you need to add them to this "main" test class as well. Changes to existing code. If you want to auto detect test cases from test classes, then you need to use reflection.

    3. All your tests and your main class to run tests are not detected by eclipse and you need to write custom debug/run configurations to run these tests. You still don't see those pretty green/red colored outputs though.

    Here is what JUnit is doing:

    1. It has assertXXX() methods which are useful for printing helpful error messages from the conditions and communicating results to "main" class.

    2. "main" class is called runner which is provided by JUnit, so we don't have to write any. And it detects the test methods automatically by reflection. If you add new tests with @Test annotation then they are automatically detected.

    3. JUnit has eclipse integration and maven/gradle integration as well, so it is easy to run tests and you will not have to write custom run configurations.

    I'm not an expert in JUnit, so that's what I understood as of now, will add more in future.

    0 讨论(0)
  • 2020-12-12 10:28

    That's not testing, that's "looking manually at output" (known in the biz as LMAO). More formally it's known as "looking manually for abnormal output" (LMFAO). (See note below)

    Any time you change code, you must run the app and LMFAO for all code affected by those changes. Even in small projects, this is problematic and error-prone.

    Now scale up to 50k, 250k, 1m LOC or more, and LMFAO any time you make a code change. Not only is it unpleasant, it's impossible: you've scaled up the combinations of inputs, outputs, flags, conditions, and it's difficult to exercise all possible branches.

    Worse, LMFAO might mean visiting pages upon pages of web app, running reports, poring over millions of log lines across dozens of files and machines, reading generated and delivered emails, checking text messages, checking the path of a robot, filling a bottle of soda, aggregating data from a hundred web services, checking the audit trail of a financial transaction... you get the idea. "Output" doesn't mean a few lines of text, "output" means aggregate system behavior.

    Lastly, unit and behavior tests define system behavior. Tests can be run by a continuous integration server and checked for correctness. Sure, so can System.outs, but the CI server isn't going to know if one of them is wrong–and if it does, they're unit tests, and you might as well use a framework.

    No matter how good we think we are, humans aren't good unit test frameworks or CI servers.


    Note: LMAO is testing, but in a very limited sense. It isn't repeatable in any meaningful way across an entire project or as part of a process. It's akin to developing incrementally in a REPL, but never formalizing those incremental tests.

    0 讨论(0)
  • 2020-12-12 10:31

    JUNIT is the method that is usually accepted by java developer. Where they can provide similar expected input to the function and decide accordingly that written code is perfectly written or if test case fails then different approach may also need to implement. JUNIT will make development fast and will ensure the 0 defects in the function.

    0 讨论(0)
提交回复
热议问题