GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing happycoding.io — Java Unit Testing Unit TestingUnit Testing
When writing code, it can be hard to know (let alone prove) that the code you wrote does the right thing. Does it handle input correctly? Does it fail gracefully when it’s given bad data? Does it deal with edge cases the way you expected? You can manually test your code to increase your confidence, but that becomes more difficult when you have multiple people working on the same code: will the next person remember to test all of the same cases you originally tested? How will they know if they change your code in a way that breaks something? Just as importantly, when you’re sharing a codebase with other people, how do you know that the code you wrote doesn’t break anything? Imagine working on a large codebase with hundreds of thousands of lines of code: how do you know that the little change you made to a library function won’t break everything? This is where unit testing comes in handy. Unit tests are small programs that you write to test out your “real” code. A unit test generally only tests out one small piece of functionality, and you’ll usually write a bunch of unit tests to make sure your code handles a variety of conditions. By running unit tests on your code, you can be more confident that your change didn’t break anything. JUnitJUnit is a library that helps us write unit tests. JUnit handles stuff like automatically setting up an environment, calling a series of test functions, and making sure that the code does what we expected through assertions. It’s probably easiest to just see an example. Consider this simple Java class: Here’s a JUnit test class that contains a single test function for the When we run this class through JUnit, JUnit sees the Notice that the Multiple TestsSo far we just have a single function that tests our For example we might want a test for negative numbers, or for very large numbers. When we run JUnit, JUnit will run each of these test functions. Notice that each test function only tests one thing! Writing tests also lets us test our own assumptions. For example, maybe we expected that overflow started over at 0 instead of at the minimum value. In that case, our test would have failed, and we would have been able to make the necessary change in our code. Even with this simple example, we could probably add more tests: checking that a mix of positive and negative numbers works how we expect, checking that adding zero works how we expect, or checking that multiple calls to the addThings() function works how we expect. You’ll often end up writing more test code than “real” code! SetupNotice that each of our test functions starts with the same line of code: We can get rid of this duplication using the Now JUnit will automatically run the Hard-codingYou’ve probably heard that using hard-coded values is generally a bad idea when we’re writing code. The opposite is true for test code! Tests should use hard-coded values as much as possible, and we should avoid putting any logic in our tests. For example, note that we’re passing a value directly into the But this actually makes the test harder to read. It also just repeats the logic that we’re trying to test, so it’s not a very valuable test. Instead, we should hardcode values as much as possible: MocksRemember that a unit test should only test one thing at a time: a single class or a single function. But what if we have code like this? This class uses another class named If A mock is an object that can be treated just like any other instance of a particular class, but without relying on any logic inside the class. Instead, we can tell our mock to return a certain value when a function is called. Creating MocksTo create a mock, we call the And then to mock out a function, we call the Now if we call VerificationTo check whether a function is called on a mock object, we can use the This function will verify that our code called Putting it all together, our test would look like this: This test function creates a mock Examining ArgumentsIf you want to take a more detailed look at the argument passed into a mock, you can use the This is just an example, and exactly what you do with the Fixing Broken TestsUnit tests confirm that your code works a certain way. So if you change the behavior of your code, your tests will break. So if you’re working in a project that contains unit tests, you’re going to spend a significant portion of your time fixing broken tests. When a test fails, the first thing you should do is check whether it’s failing in a way you expected. Understand what the test was originally doing, and look at how your code changed the behavior being tested. If the test did not break in a way that you expected, then you should take a closer look at your code to make sure it’s doing what you expected. If the test did break in an expected way, then you should modify the test to reflect the new behavior. For example, let’s say we modified our We’d then look at each failing test and make sure that the test is failing how we expected. Then we’d modify the tests to reflect the new behavior. Adding TestsIn addition to modifying the existing tests, you’ll usually want to add tests for any new behavior in any code you write. Generally speaking, any pull request that contains a code change should also contain a test change. In our example, we might add a new test for Writing code is only half the battle. You also have to add tests for the code you write! Working in Small StepsOne of the most important things to remember is that you should not be submitting pull requests that contain hundreds of lines of code and thousands of lines of tests. For the sake of the sanity of both you and your coworkers, try to work in small pieces! Try to break your problem down into smaller individual steps, and then take those steps on one at a time. This will make it easier to write tests, and your code will be easier for your coworkers to review. Try to get into the habit of going through this process:
Other Types of TestsUnit tests are designed to be small and to only test one thing at a time. This is great for verifying that individual pieces of your code work how you expect and don’t break in the future, but they aren’t great for testing a full system end to end or for testing out a user interface. Integration and UI TestingEnd-to-end tests are called integration tests and usually involve more elaborate test frameworks. For example, an integration test might start up a test server and then programmatically use the mouse and keyboard to test that the web browser does the right thing. Manual TestingUnit tests are a form of automated testing, which means that the tests run automatically and code is ultimately responsible for determining whether something is working correctly. These types of tests are good for detecting when a change in the code breaks an assumption made somewhere else in the code, but they’re not a substitute for manually testing that everything works yourself. In addition to writing tests, always make sure that the code actually works the way you expect it to. Run a local server, and click around the site as if you’re a user. Test to make sure that the previous functionality still works, and that whatever you added does what you expected it to. It’s fine to have unfinished features in your code: in fact, it’s a very good idea to break things down into small pieces and submit those pieces one at a time instead of waiting until a whole feature is done. But each of those changes should be complete enough so that it doesn’t break the rest of project! The code should compile, and everything should still work without breaking. It can be useful to come up with a checklist and run through it whenever you’re ready to submit a change. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |