Given a unit test class that needs to use a specific service, it seems that there are different ways to fake the behaviour of the service, such as using a mocking framework, or implement a stub class.
For instance, a service to read/write to disk:
public interface FileServiceInterface {
public void write(String text);
public String read(String fileName);
}
I might have a class that fakes its behaviour and later use it in the test class, injecting the Stub instead of the real implementation:
public class FileServiceStub implements FileServiceInterface {
ConcurrentHashMap<String, String> content = new ConcurrentHashMap<>();
public void write(String fileName, String text) {
content.put(fileName, text);
}
public String read(String fileName) {
return content.get(fileName);
}
}
Other option is to let Mockito (for example) intercept the calls to the service directly in the test class:
public class TestExample {
#Mock
private FileServiceImpl service; // A real implementation of the service
#Test
void doSomeReadTesting() {
when(service.read(any(String.class))).thenReturn("something");
...
}
}
I would like to know which of these alternatives is the best (or currently most accepted) approach, and if there's any other/better option. Thanks.
Short answer: depends on the use case when you need to check a behavior use Mock otherwise in the case of state-based test use Stub.
In state verification you have the object under testing perform a certain operation, after being supplied with all necessary stubs. When it ends, you examine the state of the object and verify it is the expected one.
In behavior verification, you specify exactly which methods are to be invoked, thus verifying not that the ending state is correct, but that the sequence of steps performed was correct.
Martin Fowler described a great comparison between Stubs and Mocks in the article Mocks Aren't Stubs.
There are several types of pretend object used in place of a real object for testing purposes:
Dummy objects are passed around but never actually used. Usually they
are just used to fill parameter lists.
Fake objects actually have
working implementations, but usually take some shortcut which makes
them not suitable for production (an in memory database is a good
example).
Stubs provide canned answers to calls made during the test,
usually not responding at all to anything outside what's programmed in
for the test.
Spies are stubs that also record some information based
on how they were called. One form of this might be an email service
that records how many messages it was sent.
Mocks objects pre-programmed with expectations which
form a specification of the calls they are expected to receive.
In your case we have Fake vs Mock object type.
They all look like real objects, but unlike Mocks, others types do not have pre-programmed expectations that could fail your test. A Stub or Fake only cares about the final state - not how that state was derived.
So there we have two different design styles of testing.
State based tests are more black-boxed. They don’t actually care how the System Under Test(SUT) achieves its result, as long as it is correct. This makes them more resistant to changes and less coupled to design.
But occasionally you do run into things that are really hard to use state verification on, even if they aren't awkward collaborations. A great example of this is a cache. The whole point of a cache is that you can't tell from its state whether the cache hit or missed - this is a case where behavior verification would be a wise choice.
Also good thing about Mock is the ability to define relaxed constraints on the expectation - you can use any(), anyString(), withAnyArguments(). It is flexible.
What's the difference between a mock & stub?
Related
Is there any way to write unit tests for save methods in DAO layer when return type is void? I'm using Log4j, Junit in spring boot project.
I've tried many ways to assert them. But since they aren't returning any value i wasn't able to assert them.
If the method is void, then it has side-effects, otherwise it would be a no-op.
So you call the method, then check if the desired side-effect happened.
E.g. setFoo(7) should mean that getFoo() returns 7, though unit testing simple getter/setter methods is a waste of time.
It is common to use mock objects to detect the side-effects, but it all depends on what the expected side-effect is. See: What is the purpose of mock objects?
There are several ways to unit test a method that returns void.
Change the method so that it returns a value even though you don't use that value. This is NOT the best way, but I note it here for completeness.
The method likely changes the state of the object in some way. A file was saved, a value was stored somewhere, parameters have been changed, etc. So check the values that should have been changed. You can read back a saved file, a changed variable, data in a test database, etc.
Mock objects can be used to determine if a method was called and what the behavior was. There are a number of mock object frameworks for Java, including Easy Mock, JMockit and Mockito. How to use a mock framework is beyond the scope of this answer, but I did include links to the various sites for your reference.
If bad inputs are given to the method it may throw an exception. It is a good idea to do this to test the error handling of your methods.
According to your comments you need to write an unit test for a save method. Try this example code,
#Autowired
private EmployeeDAO employeeDAO;
#Test
public void whenValidEmployee_thenShouldSave()
{
EmployeeEntity employee = new EmployeeEntity("1", "Department Name", "Role"); //id, department name and role are passing as constructor parameters
employeeDAO.save(employee);
List<EmployeeEntity> employees = employeeDAO.findAll();
//Assert
Assert.assertEquals(employee.getId(), employees.get(0).getId());
}
Writing a testable code is important as a developer in modern days. You should understand that a method with void, is bad for a single reason.it is not testable by any means. i would suggest you below actions to take
Improve your code with a relevant return type.
It's worth applying DbUnit, rather than applying just Junit to test
your DAO layer.
#Teguwih
I have some problems with unit testing the following method.
public List<GetSupplyChainResponse> getSupplyChains(){
List<GetSupplyChainsResponse> response = new ArrayList<>();
supplyChainRepository.findSupplyChainsWithCompound().forEach(result
-> response.add(getGetSupplyChainSimpleResponse(result)));
return response;
}
getGetSupplyChainSimpleResponse() is a private method of the same class as getSupplyChains()
Is there any possibility to define return values therefore or do you have any other ideas how I could test the method getSupplyChains()?
You might be overthinking this. The fact that the method that you want to test (getSupplyChains) uses a lambda that calls a private method is irrelevant: they are just implementation details.
What you unit test is the part of your class that you as a client interact with, i.e. its interface. You typically call a public method with some arguments (in this case there are none), you get some return value and that is what you verify in your unit test. If your public method makes use of some private method, it will be tested also.
The problem here is that the response that you get from getSupplyChains obviously depends on what supplyChainRepository.findSupplyChainsWithCompound() returns. What you do in this case is mock that dependency (supplyChainRepository) out: you create a mock instance of SupplyChainRepository, you tell it how to behave, and you pass it to this class, for example via the constructor.
You can either write the mock yourself, or you can rely on a mocking framework to do the heavy lifting like Mockito.
I definitely recommend against unit testing private methods (it leads to brittle tests), or increasing the visibility of those methods (a.k.a. sacrificing your design for the sake of testing).
It is a commonly discussed problem, some prefer using reflection as Janos Binder recommended (How to call a private method from outside a java class), some can live with the fact the the visibility of the methods which we need to mock is increased for the sake of testability.
The problem is quite well discussed here: How do I test a class that has private methods, fields or inner classes?. You can see from the answers and wide discussions that the topic is quite complicated and developers split into factions and use different solutions.
I'd recommend you to remove the private access modifier and to make the method package private (use the default visibility). The common custom is to have the test classes in the same package (but not in the same folder!) as the tested classes.
This will allow you to:
Test the getGetSupplyChainSimpleResponse() method itself, which you should do in any case somehow.
Mock its behaviour for the purpose of testing getSupplyChains(). This you will achieve e.g. by using Mockito framework and its #Spy functionality.
For those who argue that this is "sacrificing your design for the sake of testing", I would answer that if you have private methods which need to be mocked and/or tested, then the design is not ideal anyway so changing the visibility to package private does not mean too big deterioration. The clear solution (from the object oriented design's point of view) is to delegate the behavior of such private methods to separate classes. However, sometimes in the real life it is just overkill.
I'm working on a method that can be considered a specialization of another already defined and tested method. Here's an example code to illustrate:
public class ProductService {
public void addProduct(Product product) {
//do something
}
public void addSpecialProduct(Product product) {
addProduct(product);
//do something after
}
}
I don't want to copy the tests I have for addProduct which are already pretty complex. What I want is when I define the tests for addSpecialProduct, I just make sure that it also calls addProduct in the process. If this were a matter of 2 classes collaborating, it's easy to have the collaborator mocked and just verify that the target method gets called (and stub it if necessary). However, the 2 methods belong to the same class.
What I'm thinking right now is to spy on the object I'm testing, something like:
public void testAddSpecialProduct() {
//set up code
ProductService service = spy(new DefaultProductService());
service.addSpecialProduct(specialProduct);
verify(service).addProduct(specialProduct);
//more tests
}
However, I'm wondering whether this approach somehow defeats the purpose of unit testing. What's the general consensus on this matter?
I think it depends on how rigorous you want to be with your unit testing. In the extreme sense, unit testing should only test the behavior, not the implementation. This would mean you would need to duplicate your tests (or take take #chrylis' suggestion of abstracting out common functionality to helpers). Ensuring the other method is called is testing the implementation.
However in reality, I think your idea of spying on the instance to ensure the other well-tested method is called is a good idea. Here are my reasons:
1) It simplifies your code.
2) It becomes immediately clear to me what is happening. It says to me that everything that has been tested for the other method will now also be true, and here are the extra assertions.
One day you may modify the implementation so that the other method is not called, and this will cause your unit tests to fail, which is what people are generally trying to avoid by not testing the implementation. But in my experience, changes like this are much more common when the behavior is going to change anyway.
You may consider refactoring your code. Use the strategy pattern to to actually implement the functionality for adding products and special products.
public class ProductService {
#Resource
private AddProductStrategy normalAddProductStrategy;
#Resource
private AddProductStrategy addSpecialProductStrategy;
public void addProduct(Product product) {
normalAddProductStrategy.addProduct(product);
}
public void addSpecialProduct(Product product) {
addSpecialProductStrategy.addProduct(product);
}
}
There will be 2 Implementations of the AddProductStrategy. One does that what happend in your original ProductService.addProduct implementation. The second implementation will delegate to the first one and then do the additional work required. Therefore you can test each strategy separately. The second strategy implementation is then just a decorator for the first implementation.
I have a class that I want to test using mockito. The best way to describe the class is to paste the code, but I will try and do my best in a short phrase.
The class has one void function and calls another object that is passed in via setter and getter methods. The object that is being called (from the void function) is an asynchronous call.
The problem I am facing is mocking the asynchronous call that void function (testing via junit) uses.
public class Tester {
private Auth auth; // not mock'ed or spy'ed
#Mock private Http transport;
#Before
....
#Test
public void testVoidFunctionFromAuth() {
doAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return doOutput();
}
}).when(transport).executeAsync(param1, param2, param3...);
auth.obtainAuth(); // void function that uses transport mock class
// obtainAuth calls transport.executeAsync()
// as part of the code
}
// return type of transport.executeAsync() is
// ListenableFuture<ResponseEntity<String>>
private ListenableFuture<ResponseEntity<String>> doOutput() {
return new SimpleAsyncTaskExecutor()
.submitListenable(new Callable<ResponseEntity<String>>() {
#Override
public ResponseEntity<String> call() throws Exception {
....
return responseEntity
}
});
}
}
What happens is that the doOutput() function gets called before the auth.obtainAuth(); and when obtainAuth() tries to call doOutput() it returns null -- most likely because doOutput was already execute on the line before. I am not sure how to bind/inject the mock'ed class (transport) on the call executeAsync.
I'm not sure if I understood the question, but as chrylis pointed, the mock object returns a value instantly.
Unit test should have their own context, and not depend on external resources, so there is no point on testing the async call itself. It should return different values so you are able to test the behaviour of the classes that uses it.
To have a better understanding of mock definition take a look at this post: What is Mocking?
Quoting from Pro Spring MVC with Web Flow, a unit test should
• Run fast: A unit test must run extremely fast. If it needs to wait
for database
connections or external server processes, or to parse large files, its
usefulness will quickly become limited. A test should provide an
immediate response and instant gratification.
• Have zero external configuration: A unit test must not require any
external configuration files, not even simple text files. The test’s
configurations must be provided and set by the test framework itself
by calling code. The intent is to minimize both the runtime of the
test and to eliminate external dependencies (which can change over
time, becoming out of sync with the test). Test case conditions should
be expressed in the test framework, creating more readable test
conditions.
• Run independent of other tests: A unit test must be able to run in
complete isolation. In other words, the unit test can’t depend on some
other test running before or after itself. Each test is a stand-alone
unit. In fact, every test method inside a test should be stand-alone
and not depend on another method or on the test methods being run in a
certain order. • Depend on zero external resources: A unit test must
not depend on any outside resources, such as database connections or
web services. Not only will these resources slow the test down, but
they are outside the control of the test and thus aren’t guaranteed to
be in a correct state for testing.
• Leave external state untouched: A unit test must not leave any
evidence that it ever ran. Unit tests are written to be repeatable, so
they must clean up after themselves. Obviously, this is much easier
when the test doesn’t rely on external resources (which are often
harder to clean up or restore).
• Test smallest unit of code possible: A unit test must test the
smallest unit of code possible in order to isolate the code under
test. In object-oriented programming, this unit is usually a method of
an object or class. Writing unit tests such that a method is tested
independently of other methods reduces the number of code lines that
could contain a potential bug.
I have a pretty simple question: I've been writing some Unit tests to a command object which has a Context object. This context has some domain entities inside of it.
public class Context {
private DomainEntity domainEntity1;
private Dto dto1;
// getters and setters go here...
public boolean isDomainEntityValid() {
// a little bit of logic goes here
}
}
public class Command {
public void execute(Context context) {
// do its logic in here
}
}
The DTO and the DomainEntity have nothing but setters and getters and very simple validation methods (such as isFirstNameValid()).
The Context object does have logic in it - after all, it checks if the context is consistent, is the context is complete, and so on.
When unit testing the command object, it's pretty clear to me that the context should be mocked out - but what about the entity and dto? Should I mock them? If so, I'll have to do a lot of code like the one below
doReturn(1L).when(domainEntity1).getId();
doReturn("phil").when(domainEntity1).getName();
In the another words, a lot of behaviour for the getters methods will have to be defined.
So, bottom line: should I mock Domain Entities and DTOs when unit testing an object?
I think you're probably violating the "Law" of Demeter here. I put that in quotes because you shouldn't follow this as a law but as advice.
You're not really giving us enough context to be able to tell you what you should specifically change (ie: why does the command need the id and the name?), but there's this other principle called Tell, Don't Ask and I think if you change your code to follow that, your code will become much easier to test.
(I think I may elaborate a bit more on my comment)
Whether you need to do the mocking etc all depends on what's the logic in your System-Under-Test (SUT, in this case, your Command).
Whole idea of mocking/stubbing is we don't what our testing to SUT depends on other actual code. Therefore we make up the mocks/stubs which fit for use in test, so the validity of test only depends on SUT, but not other actual code (of course, given that your mock/stub is correctly written, but that's normally not a problem due to its simplicity)
So, if your logic of Command is something like
DomainEntity domain = context.getDomainEntity();
domain.doSomething();
then yes, you need to do the mocking for your domain entity.
However, if you are simply working against the context, like:
if (context.isDomainEntityValid()) {
doSomething();
} else {
doAnotherThing();
}
then there is no point to mock the domain entity.
One more thing to note, with help of mocking framework, you can simply do stubbing according to your SUT logic. You don't need to do stubbing for EVERY method.
Therefore, if your Command is only calling domain.doSomething(), just stub this method. Forget about DomainEntity#anotherMethod() DomainEntity#getId().