I am wriring unit test cases for an existing system. The architecture for the underlying classes if very complex in itself.
Blockquote
RequestHanndler ==> processes ==> Order ===> is dependent on ==> service layer == connected to ==> DB layer.
I am writing a test case for RequestHandler. The method in test(doProcess()) creates a new instance of Order class. Order class itself has very tight dependency on the service layer. I want to create an atomic test case, so, not any other layer of code will be executed.
What should the best process to create test cases for these scenrios?
It might get a bit complicated when you want to write unit-tests for tighly coupled code. To make uni-testing easier you should better rely on abstractions and not on real implementations. E.g. the Order class shouldn't depend on the real implementation of the service layer, instead introduce an interface which is much easier to mock instead of a class which might be set to final.
Since your RequestHandler is responsible for creating the Order instances you'll have to provide a way to mock out the order class in unit-tests. A simply way is to create a protected method that simply creates a new order instance.
protected Order createOrder(String someParam) {
return new Order(someParam);
}
In your Unit-Tests you can now extend the class and overwrite the factory-method.
Using Mockito this would look like:
protected Order createOrder(String someParam) {
Order order = Mockito.mock(Order.class); // create mock object
// configure mock to return someParam when
// String Order#getSomeParam() gets invoked
Mockito.doReturn(someParam).when(order).getSomeParam();
return order;
}
Typical approach for unit testing of such systems is mocking. There are several mockup frameworks for java. I personally used EasyMock but there are others.
So, I think that you should to try to test the logic of request handler first. You should mock Order (i.e. create dummy, not real instance of order using mockup frameork). When this layer is tested go deeper and start testing internal layers.
Other strategy is going from down to up, i.e. test first the internal layers. This strategy is probably "right" but it you will not get fast results that you can show to your manager because managers typically like to see the "big" picture and very seldom go into the details.
Bottom line: good luck.
Related
I don't know if I'm testing this method wrong or if the whole test is nonsense. (Example code is below)
I would like to test my ExampleService with Mockito. This has the client and the customerService as dependencies (both with #Mock). Both dependencies are used in exampleService.doYourThing().
client.findByName() returns a ResultPage, which in turn is used in customerService.createHitList(). I thought it would be a good idea to test that the page object does not change during the "doYourThing" method, after being returned by client.findByName(). Therefore, customerService.createHitList() should only return something if 'page' does not change.
The problem: If 'page' is returned in "doYourThing()" by client.findByName() and is changed with "page.setIsNew(true)" as in my example, then in my test method the 'pageForTest' object also changes. As a result, the condition I set with "given(this.customerService.createHitList(pageForTest))" is met and the customerList is returned.
I know that 'page' is a reference of 'pageForTest' and thus changes.
Anyway, the goal of my test is not fulfilled by this. How would you tackle the problem?
This is only sample code, there may be small syntax errors.
Test method:
ExampleService exampleService = new ExampleService(client, customerService);
ResultPage pageForTest = new ResultPage();
pageForTest.setIsFulltextSearch(true);
pageForTest.setIsNew(false);
pageForTest.setHits(hits);
given(this.client.findByName("Maria")).willReturn(pageForTest);
given(this.customerService.createHitList(pageForTest)).willReturn(customerList);
HitList hitList = this.exampleService.doYourThing("Maria");
ExampleService
public HitList doYourThing(String name) {
ResultPage page = this.clientFindByName(name);
page.setIsNew(true);
HitList hitList = this.customerService.createHitList(page);
return hitList;
}
When writing unit tests it's important to actually define the unit. A common misconception is treating every class as a separate unit, while we use classes to separate responsibilities, but a certain unit of work can be represented by more than one class (so it could include more than one responsibility as a whole). You can read more about it on the Internet, for example on the Martin Fowler's page.
Once you define a unit you want to test, you will need to make some assumptions regarding the dependencies used by the test. I will point you towards the Martin Fowler's page for more information, but in your case this could be a mock of the repository retrieving some data from the database or a service representing another unit, which has it's own tests and it's behavior can be assumed and reproduced using a mock. The important thing is that we do not say here that all the dependencies should be mocked, because maybe testing given method while mocking all the dependencies only tests Mockito and not actually your code.
Now it's time to actually understand what you want to test - what is the actual logic of the code. When developing using test-driven development, you write the tests first as the requirements are pre-defined and the tests can point you towards the best API that should be exposed by the class. When you have tests ready, you implement the code as designed during writing the tests. In your case you have your logic ready and let's assume it's doing what it's supposed to do - that's what you want to test. You are not actually testing the code, but the desired behavior of the code. After the test is written, you can change the code in many ways including extracting some parts to a method or even a separate class, but the behavior should be well defined and changing the internals of a method or the class (refactoring) should not require changing the tests, unless API or the expected behavior changes.
The main problem with trying to help you understand how to test your code is actually the lack of context. Method named doYourThing does not describe the expected behavior of the method, but this is actually the most important thing when writing a test - that thing should be done. If you strictly stick to how it's done internally in your test, the code will be hard to modify in the future and the tests may be unreliable. If the important behavior includes setting the isNew value, maybe the object returned from the mock should be a spy or it should be verified with assertions? If the actual logic lies in the customerService, then maybe it shouldn't be mocked, but it should be the part of the unit? It requires context, but hopefully I explained some things regarding testing as a concept. I recommend reading up on testing online as multiple articles like those by Martin Fowler can be more helpful in understanding it.
I'm aware that there are many questions about mocking and testing, but I didn't find any that helped me perfectly, so I still have problems understanding the follwing:
Please correct me if I got this wrong, but as far as I see, unit tests are used to test the business logic of one particular class in isolation and if there are any objects needed from the outside they will be mocked.
So for example if I have a management system for citizens of a simple city that adds citizens to a list and returns the citizen by their names (Assumtion: citizens consist of only a few basic personal information), like this:
public class ProcessClass {
ArrayList<Citizen> citizenList = new ArrayList<Citizen>();
public void addCitizen(Citizen citizen) {
citizenList.add(citizen);
}
public Citizen getByName(String name) {
for (Citizen c : citizenList) {
if (c.getName().equals(name)) {
return c;
}
}
return null;
}
}
If now I want to unit test my ProcessClass do I consider Citizen as an external feature that has to be mocked, or do I simply just create a Citizen for test purposes?
If they are mocked, how would I test the method to get the object by its name, since the mock object is not containing the parameters?
As you're writing new code (along with the new unit tests) or refactoring existing code, you want to be able to run the unit tests over and over to be reasonably confident existing functionality was not broken. Therefore, the unit tests must be stable and fast.
Suppose the class to be tested depends on some external resource such as a database. You make a code change and the unit tests are suddenly failing. Did the unit tests break because of a bug you just introduced, or because the external resource is not available? There is no guarantee the external resource will always be available so the unit tests are unstable. Mock the external resource.
Also, connecting to an external resource can take too much time. When you eventually have thousands of tests which connect to various external resources, the milliseconds to connect to the external resource add up, which slows you down. Mock the external resource.
Now add a CI/CD pipeline. During the build the unit tests fail. Is the external resource down or did your code change break something? Perhaps the build server doesn't have access to an external resource? Mock the external resource.
To answer the first part of your question
If now I want to unit test my ProcessClass do I consider Citizen as an external feature that has to be mocked, or do I simply just create a Citizen for test purposes?
Without knowing more about Citizen it is hard to tell. However, the general rule is, that mocking should be done for a reason. Good reasons are:
You can not easily make the depended-on-component (DOC) behave as intended for your tests.
Does calling the DOC cause any non-derministic behaviour (date/time, randomness, network connections)?
The test setup is overly complex and/or maintenance intensive (like, need for external files)
The original DOC brings portability problems for your test code.
Does using the original DOC cause unnacceptably long build / execution times?
Has the DOC stability (maturity) issues that make the tests unreliable, or, worse, is the DOC not even available yet?
For example, you (typically) don't mock standard library math functions like sin or cos, because they don't have any of the abovementioned problems. In your case, you need to judge whether just using Citizen would cause any of the abovementioned problems. If so, it is very likely better to mock it, otherwise you better do not mock.
More often than not, mocking is used to replace actual calls that are hard to duplicate in testing. For instance, assume ProcessClass makes a REST call to retrieve Citizen information. For a simple unit test, it would be hard to duplicate this REST call. However, you can "mock" the RestTemplate and dictate the different types of returns to insure your code would handle the 200's, 403's, etc. Additionally you could change the type of information to then also test your code to insure that bad data is handled, like missing or null information.
In your case you can actually create a Citizen, and then test that the Citizen is an object in the list or that getByName returns the proper object. So mocking is not needed in this example.
In your particular example, no, you would not need to mock anything.
Let's focus on what you would test:
a test where you add and retrieve one Citizen
add 2 Citizens, retrieve one
pass null instead of citizen, and make sure your code doesn't break.
add two citizens with the same name, what would you expect to happen then?
add a citizen without a name.
add a citizen with a null name
etc etc
You can already see a number of different tests you can write.
To make it more interesting you could add some code to your class which exposes a read-only version of your citizenList, then you could check that your list contains exactly the right things.
So, in your scenario you don't need to mock anything as you don't have external dependencies on another system of some kind. Citizen seems to be a simple model class, nothing more.
If they are mocked, how would I test the method to get the object by its name, since the mock object is not containing the parameters?
You can mock the call to getName, using mockito for example:
Citizen citizen = mock(Citizen.class);
when(citizen.getName()).thenReturn("Bob");
Here is an example of a test for your method
ProcessClass processClass = new ProcessClass();
Citizen citizen1 = mock(Citizen.class);
Citizen citizen2 = mock(Citizen.class);
Citizen citizen3 = mock(Citizen.class);
#Test
public void getByName_shouldReturnCorrectCitizen_whenPresentInList() {
when(citizen1.getName()).thenReturn("Bob");
when(citizen2.getName()).thenReturn("Alice");
when(citizen3.getName()).thenReturn("John");
processClass.addCitizen(citizen1);
processClass.addCitizen(citizen2);
processClass.addCitizen(citizen3);
Assert.assertEquals(citizen2, processClass.getByName("Alice"));
}
#Test
public void getByName_shouldReturnNull_whenNotPresentInList() {
when(citizen1.getName()).thenReturn("Bob");
processClass.addCitizen(citizen1);
Assert.assertNull(processClass.getByName("Ben"));
}
Note:
I would recommend mocking. Let's say you write 100 tests where you instantiate a Citizen class this way
Citizen c = new Citizen();
and a few months later, your constructor changes to take an argument, which is an object itself, class City for example. Now you have to go back and change all these tests and write:
City city = new City("Paris");
Citizen c = new Citizen(city);
If you mocked Citizen to start with, you wouldn't need to.
Now, as it is POJO and its constructor of the getName method might not change, not mocking should still be ok.
I am new to Unit Testing and recently tried my hands on JUnit test and Mockito.
I am trying to unit test a method that calls multiple private methods and also creates private objects of other classes.
How can I unit test the method.
For Example if I have the following code:
class ClassToTest {
private OuterClass outerClass;
public Boolean function() {
outerClass = new OuterClass(20);
return innerFunction(outerClass.getValue());
}
private Boolean innerFunction(int val) {
if (val % 2 == 0)
return true;
return false;
}
}
I'm confused how would I test the public function.
It doesn't matter how a method is implemented; that method should have a contract it obeys and that is what you are verifying with your test. In this example, function() should return true if the outerClass's value is even. One way to accomplish this would be to inject (pass into the ClassToTest constructor) the instance of outerClass so that you can control the value when testing:
#Test
public void trueWhenEven() {
var outer = new OuterClass(2);
var ctt = new ClassToTest(outer);
assertTrue(ctt.function());
}
Sometimes the contract is just that a method invokes methods on some other objects; in these kinds of cases, you can use Mockito or similar library to verify the interactions.
You are starting unit-testing with directly going at some non-trivial questions.
Question 1: How to handle implementation details / private functions? Answer: Unit-testing is about finding the bugs in your code, and that is one primary goal of unit-testing (and most other kinds of testing). Another primary goal is to prevent the introduction of bugs by acting as regression tests when the software is changed. Bugs are in the implementation - different implementations come with different bugs. Therefore, be sure to test the implementation details. One important tool to support here is coverage analysis, which shows you which parts of the implementation's code have been reached by your tests.
You may even test aspects beyond the contract of the function: a) Negative tests are tests that intentionally check behaviour for invalid / unspecified inputs, and are important to make a system secure. Because, even when provided with invalid input, the system should not allow to be hacked because of, for example, reading or writing out-of-bounds memory. This, however, does probably not apply for your example, because your method most likely is specified to implements a 'total function' rather than a 'partial function'. b) Tests of implementation details (if accessible) can even be performed beyond what is needed by the current implementation. This can be done to prevent bugs in upcoming changes to a component, like, extensions of the API.
There are, however, also secondary goals of unit-testing. One of them is to avoid that your tests break unnecessarily when implementation details change. One approach to also reach the secondary goal is, to test the implementation details via the public API. This way certain kinds of re-design of the implementation details will not break your tests: Renaming, splitting or merging of private functions would not affect the tests. Switching to a different algorithm, however, likely will require you to re-think your tests: Tests for an iterative / recursive implementation of the fibonacci function will look different than for an implementation using the closed-form-expression from Moivre/Binet, or for a lookup-table implementation.
For your example this means, you should try to test the functionality of your private function via the public API.
Question 2: How to deal with dependencies to other parts of the software? Unit-testing focuses on finding the bugs in small, isolated code pieces. When these code pieces have dependencies to other code parts, this can negatively influence your ability to unit-test them properly. But whether this is really the case depends on the actual dependency. For example, if your code uses the Math.sin() function, this is also a dependency to a different code part, but such a dependency does typically not harm your ability to properly test the code.
Dependencies to other components bother you in the following cases: The use of the other components makes it difficult to stimulate all interesting scenarios in your code under test. Or, the use of the other component leads to non-deterministic behaviour (time, randomness, ...). Or, the use of the other components causes unacceptably long build or execution times. Or, the other component is buggy or not even available yet.
If all of these criteria are not met (as it is normally the case with the Math.sin() function), you can typically just live with the other components being part of your tests. You should, however, keep in mind that in your unit-tests you still focus on the bugs in your code and do not start to write tests that actually test the other components: Keep in mind that the other components have tests of their own.
In your example you have chosen Outerclass to have some apparently trivial functionality. In this case you could live with Outerclass just remaining part of your tests. However, it is only an example from your side - The real other class may in fact be disturbing according to the above criteria. If that is the case, then you would somehow have to manage that dependency, which all requires in some way to come to a design that is testing-friendly.
There is a whole family of approaches here, so you better search the web for "design for testability" and "inversion of control". And, you also should try to learn about what distinguishes unit-testing and integration testing: This will help you to avoid trying to apply unit-testing on code parts that should rather be tested with integration testing.
Generally with Mockito this would require the use of Dependency Injection and then you would inject a mock of OuterClass for the test.
If you'd really like to test this without a Spring type framework being added I can think of 3 options:
1) Make this an Integration Test and test the real instances of everything
2) Alter your code so that OuterClass is created via a passed in Object from a setter or a constructor and then pass in a mock for your test
3) Change private OuterClass outerClass; to protected OuterClass outerClass; and make sure your test package structure is the same as your actual code package structure and then you can do outerClass = Mockito.mock(OuterClass); in your test set up.
I have a facade class, which implements the following method: getTotalNumOfItems(Query query). The facade stands in front of two other service classes, which implement the same method. Depending on the type of the query parameter, the facade decides whether to delegate to one of the services or the other.
My dilemma is how to write a unit test for the facade, without the test having to know how the number of items is derived. Otherwise, it would look like an integration test, and not a unit test anymore.
I have provided in-place mock versions of the two services, using Mockito. However, when I write a unit test for this, the only thing I can test is "verify if the facade returns a number, equal to what one of the mocks returns (depending on query type)". There does not seem to have a way to test the facade in a way more agnostic than that.
Am I doing something wrong here? Should I be feeling worried? I guess, the nature of the facade is such that its efficiency can only be verified by getting to know the classes that it delegates to. Of course, I made sure to write unit tests for the same method, in both of the services.
As you already said the responsibility of the facade is to decide to which service to delegate to. That is what you need to test. The return value of the service is of no interest for the test. So for your mocks just make sure in one test case one of those is called and the other is never invoked. And a second test case should test it's the other way round.
I have three classes I need to test, lets say Load, Transform, Perform and they all begin or work on the same data object, at least that's what is required, from one data object X the Load methods perform their thing on it, then it is given to Transform which also does its thing with its methods, and a Perform which changes the data object a bit and it is ready.
Now I want to write tests for Load, Transform and Perform.
The test-data object, should I just make a static method in the Load class like
public static TestData makeTestData(...makeit...)
OR should I make a TestDataMock or TestDataTest class ? Which can return an example of it? And make a new TestDataTest class in each Load, Transform and Perform when they need to work on it?
You should always strive to make unit tests independent of each other. For that reason, you should always create any input test-data fresh for each test, whenever possible. What you want to test is "given input data X, verify that output is Y". JUnit has the #Before annotation which you can use to annotate a method that is to be run before each test-case in that class. Typically, that is where you would put all your set-up code (creating and initilizing mock objects, creating or loading test-data, etc).
Alternativly, you could combine your Load, Transform and Perform actions into one test-case, but that would be more of an integration test than a unit test.
Sounds like a good example where dependencies would be useful, so you don't have to recreate the object every time (or worse, mock it). On top of that, you work with the real output produced by the previous phase, and you don't have to use statics (always a code smell).
JUnit doesn't support dependencies, but TestNG does:
#Test
public void load() { ... }
#Test(dependsOnMethods = "load")
public void transform() { ... }
#Test(dependsOnMethods = "transform")
public void perform() { ... }
If transform() fails, the final report will say "1 Passed (load), 1 Failed (transform) and 1 Skipped (perform)", and you know exactly where to look.
Most test-case classes should be in the style of testcase class per class: if your have a class X it has one corresponding class XTest. But that is not the only way of doing things; if you have a group of classes that cooperate you could use JUnit for some low-level integration testing of the cooperating classes. You need only think of a suitable name for this test-case class.
However, if you have a group of cooperating classes, consider hiding that fact behind a facade, or even just a single method call of some higher-level class. Then treat that facade or high-lelve method as something to unit-test.
Or, are you trying to say that you do not know how to test your three classes in isolation because they are very tightly coupled, and the behaviour of one can not be described without reference to the two others? That suggests you have a poor design: consider a redesign so you can describe the required behaviour of each class in isolation, and therefore test them (at least in part) in isolation.