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.
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 trying to write a unit test for an implementation of a Feign client. I wasn't sure how to go about it so I googled it and came across this answer and the accepted answer is this code snippet:
#Test
public someTestClient(){
Person expectedPerson = new Person("name",12));
when(mockPersonClient.getPerson()).return(expectedPerson);
Person person = mockPersionClient.getPerson();
assertEquals(expectedPerson, person);
}
I don't understand why this is a useful test or under what circumstance, other than a problem with the Person constructor, this test could ever fail. Isn't this test essentially the equivalent of:
Person person = new Person("a", 1)
Person expectedPerson = new Person("a", 1)
assertEquals(person, expectedPerson)
I understand unit testing should test functionality in isolation. Will this test just ensure that mockPersonClient exists at runtime?
We can configure a mock object to always return a hard coded and fake object when calling a method on that mock object.
In this example , the OP configured mockPersonClient.getPerson() return a fake Person.However, he just wonder why the fake person was not returned as configured when he called mockPersonClient.getPerson(). I think the codes example he shown was just for him to demonstrate this question. It does not mean he actually wrote that unit test codes to test some production codes.
A test like that doesn't have any value.
Here is a person, I am going to ask this call to return person and then I will check I got person when calling that thing. Of course you will get person, you just hard-coded that, so how is it useful?
Unit tests are about functionality, a simple fact which is lost on many.
Any code which changes data, which filters something, which changes something in a controlled way, is a good candidate for a unit test.
People use mocks a little bit too much and for most of the time for the wrong thing. Yes, we are advised to code against interfaces, but this doesn't mean you should have a very complex system, where you pass interfaces all over the place and then your test code tries to mimic that.
When you mock too much, it means the test you are writing is tied too much to the code it tests, it knows too much about it. Unit tests should not do that, because every time you change the code in some small way, you then discover that now you have to change the test, because you're no longer using 35 interfaces, now you have 47 to mock in a very specific order. That may not be an issue when you have one test, but imagine what happens when you have 1000 tests ...
If people tried to code in more of a functional way then this would not happen. If you pass data, instead of abstractions, now you don't have to mock anything.
Instead of mocking a call a database, isolate it, take the result and pass that to a method, you've just lost an abstraction and your code does not need to mock anything, you just call the method, pass the data in whatever format you want and see what happens.
If you want to test a real database, then you write an integration test. It's really not that complicated, mocking should not be the first thing you do, do it when it helps and you really must, but most of the time, you really don't and it simplifies things if you don't.
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 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.
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.