I have a class that is responsible for network communication. I would like to have a unit test for it.
Here is where I'm stuck in order to write a test for it i have to implement a server to communicate with but that in turn will require its own test.
How do you write tests for a class such as this?
Unless you are writing low level drivers, your class undoubtedly depends on other classes to do the actual communications. In that event, I would use dependency injection to supply those classes or wrappers around them, if they aren't easily mocked. In you tests, you'd supply a mock version of the classes you are depending on (or the wrappers if you can't mock the actual classes). Verify that the correct methods with the proper parameters are invoked by your methods on the mocks that you supply. Make sure you have enough unit tests to satisfy yourself that you've covered the full range of behavior from the real dependencies. This will suffice for your unit tests.
You will also need some integrations tests. Unfortunately, the easiest way to do this is probably to develop a full-up mock server to communicate with. Note that your mock server need only implement the interface -- not the actual code on the other end. Supply some extra methods to allow you to set the server up for your integration tests so that the expected behavior with the mock server occurs.
If you're unit-testing a class that's responsible for network communication, then you only test that you're doing the communication correctly. So supply a mock (as in, a dummy) server for it to communicate with. There are many mock libraries that you can use such as EasyMock and jMockit. If you want to test an actual communication with an actual server, then that's integration-testing. Of course, the exact definition of what unit-testing encompasses varies from developer to developer.
Related
So I got a task where I have to verify the REST response of a remote micro service.
For now, I built an app that calling the given REST endpoint and now I have to verify the result.
My question is, where should I write the tests? If I write into the test scope with Junit/TestNG it should be unit tests with mocked objects, right?. But in this case, I couldn't test the remote service correctly.
Is it a bad pattern to call real service from test scope using Junit?
Thanks!
It really depends on the trade-offs that you'll need to make and could generally be pretty difficult to move towards a reliable state. For instance, if you wanted to test in QA but other teams have different philosophies on what QA is and happens to use it like a local development environment, their services are probably failing more often than it probably would have otherwise. In that case, when you want to run integration tests with real services that other teams own, chances are your tests may not be too indicative whether your services ran correctly. It could be the service dependency failing that trips failures when testing your services.
In that scenario, I would mock out downstream services that your team does not own because its out of your control. This could be mocking it by spinning up a web service that responds with JSON or XML payloads or whatever metalanguage the service you're consuming responding with. It could also be mocking it at the request client level meaning the lowest level of the library that sends the request.
As an effect, that means the requests that go to your service will go through all the layers of logic in your service without any mocks to the lowest possible part where your team has control over. It's based on black box testing where the service dependencies are isolated with the assumption that the other team is properly versioning their services or providing backwards compatibility. This type of testing is the less costly to maintain if you have ever seen the testing pyramid. The gist of the pyramid is that the more integrative your tests, the costlier it is to maintain and build.
If you want even more guarantees, you can combine this with contract driven tests. Essentially, another test suite that tests downstream services and making sure that they still adhere to the payload schema that your service depends on. This way, you can decouple these two sets of tests without having to worry about all the logic that comes with it. It is also more transparent in terms of failures as you will know whether your service failed or the service dependency failed.
That would be the strategy and I would advocate for using an acceptance testing framework like Cucumber to actually do the job. There are many variants of Cucumber but essentially, you would be writing behavioral driven tests (that even the product owner can read) that is parsed by a language of your choice. See this link for details.
I have a class used for handling a connection to an external system.
The class has some a few public methods, let's say:
close()
configure()
send()
connect()
And a handful of private methods.
The class is intended to hide most of the re-establishing, fail-checking and connection-handling in the internal works.
Now, I get a code coverage error on this, since there is no unit tests for this class, besides the configure-method.
Is there another way of writing unit tests for such classes, except for heavy mocking?
If so, isn't that a good proof the class should be tested at an intergration-test or system-test level rather than unit-test? Do communication-classes belong to unit-tests or system tests?
As long as you cannot instantiate the external system locally in an unit test, this task is a classical integration or system test. So the communication classes, typically do not belong to unit tests.
The coverage will be low for such classes, showing that there is
need to test them otherwise.
Further the coverage report, e.g in SonarCube can (hopefully) be filtered.
One could define exception filters, together with the responsible person (e.g Software Architect.)
It may help to move all such communication classes to its own package.
Or even to its own project or jar file. For that project the coverage would then not be executed.
Sometimes it makes sense to build a dummy external system, to work with.
If the external system is yet under development and when it changes its interfaces daily, you can lose much time in using the external system.
In such situations a dummy system can be used, which is maybe instantiable from the unit test, too.
That depends on the amount of code in the class. If it just configures another service (like a socket or a database driver), unit testing doesn't make sense since someone probably already tested the actual service.
If the code is very complex (error handling, data transformation), you should write unit tests for this part of the code and mock the service out.
I would like to know what would be the impact if a unit testing framework (for Java specifically) does not use any of the Reflection facilities. For example, if junit doesn't use Reflection at all to invoke tests, what will be the impact on its usage or features that it currently supports. Are there any alternatives to match the flexibility of Reflection APIs?
Reflection is used for configuration purpose. So the runner will know what methods to run for test and what methods to use for the setup and teardown of the tests. You could put that kind of configuration in an external file like xml and read it from there.
After knowing the names of the methods for running, reflection is used to actually allocate the methods and run them. I don't see a way you can do it in another way unless you actually write a some kind of a function in which you specifically call each test method. And then call this function in a main test suite function. Or you could make a preprocessor that write that kind of function for you from the information you specify in the configuration. But why would you want to ? It will only save you the time of the test runtime checks vs the one time compilation. It has very little advantage.
I have a service, which works as a mediator between two other services. It basically validates the inputs, then passes them to those two service sequentially (by trying to keep transactional integrity), and then, if everything goes well, saves a result to the database.
My problem now is to test this service in isolation. Of course, I can provide stubs to satisfy the dependencies. I can also test the validation of inputs, whether appropriate data is saved in the DB in a normal case, as well as whether transactional integrity is kept if any of the dependencies throws an exception.
Yet, this is only half of what the service really does. My dilemma is if I should try to prove whether the other two dependency services actually processed the data appropriately as well? The scope of my service is quite broad, so I guess it is better to also know if the dependency services also did their job well. Yet, this gets out of the scope unit testing, and moves into integration testing, right?
I am kind of confused here.
If you're asking about unit-testing, then the way to do it is to test the class in isolation using mocks or stubs.
BUT, if you feel that just doing that is not enough, you can write some component tests, where you use the all the real classes you want to test, and use a stub (or inmemory) database and mock some of the dependencies that you consider not important for what you are trying to test.
In the past, I've tested small clusters of classes that had a high interaction between them in this way (and sometimes skipping unit-tests for those classes, as the component tests covered all the scenarios). Obviously, the problem with doing this is that the number of scenarios grows almost exponentially the more classes you're testing. Maybe you can test the bridge and the 2 real classes that use that bridge.
You should do both.
For unit testing, definitely use mock-objects for dependencies, preferrably using a tool like EasyMock. As a sidenote, if you feel that the functionality of your mediator service is too broad for unit testing, you may want to consider breaking it down into smaller pieces.
Of course, you additionally should do integration testing as well, using real dependencies, to make sure your services work together as intended.
Can I create a junit environment without file system and network access? I want to enforce stricter rules for our test cases.
Ideally, this would be configurable with maven and work for the default test phase.
Based on this answer https://stackoverflow.com/a/309427/116509, I think you could set a SecurityManager on test setup and restore the original on teardown.
However, IMHO, some unit tests should be allowed to touch the file system, if for example the class under test actually creates files as part of its contract. (You can use dependency injection to make sure the files are created in a temp directory). Likewise, a good unit test of a class that uses HTTP should test it against an HTTP endpoint. Otherwise you just end up mocking everything and your test becomes worthless. I suppose the default should be to deny access, and then a developer would need to specifically override the permissions for this kind of test.
The typical way to handle these dependancies on a file system/network access, is to mock them out in a test context. This way, the real code can go through the normal channels, but your tests don't have to rely on a file system or a network.
Look into mocking frameworks to help you do a lot of this. Enabling this kind of testing will also make your code cleaner, too. :)
You can use Ashcroft to prohibit access to file system and other resources from your tests. It uses Java Security manager to restrict access to certain resources.
Another approach would be to use AspectJ and implement several advices prohibiting calling certain APIs or packages.
I'm not sure what you mean by JUnit environment, but you should not need a file system, or network access to run unit tests. On the other hand, if you are testing code that uses network and filesystem APIs, you may have an issue. In that case, you may need to abstract your code into smaller testable chunks. You should not be testing weather the network and filesystem APIs are working in a unit test, these are integration tests. You should only be testing your code in unit tests.