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().
Related
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?
For example, the class to be tested is
public class toBeTested {
private Object variable;
public toBeTested(){
variable = someFactory(); // What if this someFactory() sends internet request?
// Can I mock "variable" without calling
// someFactory() in testing?
}
public void doSomething(){
...
Object returnedValue = variable.someMethod(); // In testing, can I mock the behavior of
// this someMethod() method when
// "variable" is a private instance
// variable that is not injected?
Object localVariable = new SomeClass(); // Can I mock this "localVariable" in
// testing?
...
}
}
My questions are as stated in the comments above.
In short, how to mock the variables that are not injected but created inside the to-be-tested class?
Thanks in advance!
Your question is more about the design, the design of your class is wrong and it is not testable, It is not easy (and sometimes it is not possible at all) to write a unit test for a method and class that have been developed before. Actually one of the great benefit of TDD(Test Driven Development) is that it helps the developer to develop their component in a testable way.
Your class would have not been developed this way if its test had been written first. In fact one of the inevitable thing that you should do when you are writing test for your component is refactoring. So here to refactor your component to a testable component you should pass factory to your class's constructor as a parameter.
And what about localVariable:
It really depends on your situation and what you expect from your unit to do (here your unit is doSomething method). If it is a variable that you expext from your method to create as part of its task and it should be created based on some logic in method in each call, there is no problem let it be there, but if it provides some other logic to your method and can be passed as parameter to your class you can pass it as parameter to your class's cunstructor.
One more thing, be carefull when you are doing refactoring there will be many other components that use your component, you should do your refactoring step by step and you should not change the logic of your method.
To add another perspective: If faced with situations in which you have to test a given class and aren't permitted to change the class you need to test, you have the option to use a framework like PowerMock (https://github.com/powermock/powermock) that offers enhanced mocking capabilities.
But be aware that using PowerMock for the sole purpose of justifying hard to test code is not advisable. Tashkhisi's answer is by far the better general purpose approach.
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'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.
In Java (in an Android specific context, but this should apply across the board), is it considered bad practice to remove a private modifier - and thus be package specific - for the sake of unit testing?
Say I have something like the following:
public void init(long id) {
mId = id;
loadItems(1);
}
public void refresh() {
loadItems(mId);
}
private void loadItems(int page) {
// ... do stuff
}
In this case, I have 2 public methods that should definitely be tested. The concern is that both the refresh() and init() methods are almost identical minus some logic around handling the id.
It seems like it'd be easiest to write a unit test for loadItems() and then just verify that both init() and refresh() call loadItems() with the appropriate id (using something like Mockito). There's not a "good way" to test private methods though.
Would doing that make me a bad software developer? I know private methods technically shouldn't need unit tests, but this would be a straightforward testing approach, IMO, especially if loadItems() is somewhat complex.
You aksed "Would doing that make me a bad software developer?".
I don't think it makes you a bad developer. If you look at .NET for example, they even have a way to allow other libraries to see the internals of another library for the purpose of unit testing (InternalsVisibleTo).
I am personally against testing private methods though. In my opinion unit testing should be done on visible methods and not private methods. Testing private methods kind of defeats the point of encapsulation and making a method more visible than it needs to be just for the sake of unit testing looks wrong to me.
If I were you, I would instead test both my public methods. Today, your two methods are almost identical and it's easier to test your private method by making it package visible. Tomorrow however, that may no longer be the case. As both methods are public and easily accessible to other classes, you may be testing the wrong thing if such a scenario happens and the two drift apart.
Better yet (and this is what I would recommend) is to move
private void loadItems(int page) {
// ... do stuff
}
to its own class with its own interface and then test loadItems(int page) once using a separate unit test and then test the two public methods by just making sure they call the interface with the arguments you're expecting. This way, you're testing your entire code and avoid the pitfall I explained above.
IMHO it is better to have tests than not to, if it makes the code better and easier to maintain I think its a good idea.
I also agree with Niek above re putting the logic in another class.
I would also add that the method is void, and so has side effects which I think are harder to test than simply asserting a returned value.
Perhaps consider something like
List loadItems(int page)
Then check the list returned.