Independent JUnit Tests with Springs #Autowired - java

As a beginner in Test Driven Development I just encountered a problem. My test class begins as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
#DirtiesContext
#ContextConfiguration(locations = {"/web-test.xml"})
public class XXTest {
#Autowired
XX xx;
#Autowired
HibernateTemplate template;
#Test
public void testSetGetXXValue() throws Exception {
final Map<String, YY> profilMap = new HashMap<String, YY>(2);
profilMap.put("1", new YY());
profilMap.put("2", new YY());
simpleCockpit.setValues(profilMap);
assertEquals(profilMap, simpleCockpit.getValues());
}
As you can see, the first test method alters the autowired XX-class. That affects all following test methods, which relies on XX having the autowired-values.
How can I test getter and setter from XX AND make sure XX has the autowired values for the rest of the test methods?
Thoughts:
Reset the right values at the end of test method. Bad because if the getter / setter are not working, this will also not work.
Place the first test method at the end of the test class. Bad because that makes the tests dependent on their execution order.
Do not test the getter / setter of XX. Bad because getter / setter have to be tested like every method.
Thanks for you answers! I`m pretty sure this has an easy solution ... :)
EDIT: Regarding the questions whether unit testing getters/setters or not, I decided to do so mainly because of the reasons statet at http://www.sundog.net/sunblog/posts/should-we-test-getters-and-setters/ .

If you modify an spring managed bean, then you could use the #DirtiesContext Annotation. This Annotation can be put on Test Classes as well as on Test Methods!
From #DirtiesContext Java Doc:
Test annotation which indicates that the {#link
org.springframework.context.ApplicationContext ApplicationContext}
associated with a test is dirty and should be closed:
after the current test, when declared at the method level
after each test method in the current test class, when declared at the class
level with class mode set to {#link ClassMode#AFTER_EACH_TEST_METHOD
AFTER_EACH_TEST_METHOD}
after the current test class, when declared
at the class level with class mode set to {#link ClassMode#AFTER_CLASS
AFTER_CLASS}
And even in Test Driven Development (to my understanding): write explicite tests only for stuff that has a minimum complexity. So I never write explicite tests for getter and setter. I normally have a test that checks some functionality, and when this functionality needs the getter and setter so I write this getter and setter (at this point in time) and that they works will be checked by the functionality I started with implicit.
Especially in your case: why do you use the Spring Bean, why not using "normal" Objects created with new. I use the "normal" classes as long as it is usefull for the tests, mostly for simple tests. I use Spring Beans for "bigger" tests as well.

Related

Creating a configurable JUnit library to test same features across several microservices

A set of tests should be run on every microservice. Current solution is to have an abstract class and extend in every service, providing the necessary properties in abstract getters.
public abstract class AbstractTest {
#LocalServerPort
protected int serverPort;
protected abstract String getPath();
#Test
void someTest() {}
#Test
void conditionalTest() {}
}
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
classes = {...})
#ActiveProfiles(...) // etc
public class MyTest extends AbstractTest {
// ... implement getPath()
// tests from parent will be executed
}
The goal:
Ditch inheritance and have the AbstractTest's logic get executed automatically with conditional #Test execution based on beans/properties etc.
The possible solution:
A concrete class with all the tests or some sort of Configuration/TestFactory to create the necessary tests. It should take into account available properties and beans to determine which tests to run.
The problem:
How can those tests (created in runtime) be discovered and registered for execution?
How to inject all the properties that are part of the current context of the #SpringBootTest?
Failed attempts:
TestInstanceFactory extension doesn't seem to be the solution as it requires an instance of the class which it annotates.
Using the Launcher API seems overkill, and also doesn't seem to work, since the library class won't be created with the Spring context configs.
using cglib and a base class Spring Contract-style is not a desirable solution
Ideally I don't want the client of this lib to implement/create anything, so abstract String getPath(); would be a test.lib.path property, and if it's present, a test from the library which uses it will run.
Any thoughts on this would be great, because right now this just seems impossible to me.
What is the reason to have the inheritance for tests?
In case you need to share some common logic within the tests you may try JUnit features (custom rules/extensions), for example
For junit < 5.x.x #Rule functionality https://junit.org/junit4/javadoc/4.12/org/junit/rules/TemporaryFolder.html https://stackoverflow.com/a/34608174/6916890
For junit >= 5.x.x (jupiter) there is an extension API
https://junit.org/junit5/docs/current/user-guide/#writing-tests-built-in-extensions-TempDirectory

How to set Mock to have a default behavior and can override it in some test

I want to mock a dependency and return a default value in most test cases since most of them should not care about the values returned but there are some certain cases like I would like to test like the dependency returns some weird values or just throw. So I am modeling it in this way. Most cases, it should return a nice and valid value.
Test Setup which return the 20L by default for all test classes.
Dependency dependency = Mockito.mock(Dependency.class);
when(dependency.returnSomeVal()).thenReturn(20L);
In a specific test cases class, I would like to override the behavior like below:
when(dependency.returnSomeVal()).thenThrow(); //failure cases
when(dependency.returnSomeVal()).thenReturn(Weird_Val); //failure cases
But I don't find a good solution to override the existing behavior? Any idea?
You can reset the mock and add behavior. In the test, do
Mockito.reset(dependency);
when(dependency.returnSomeVal()).thenThrow(); //failure cases
when(dependency.returnSomeVal()).thenReturn(Weird_Val); //failure cases
Resetting will remove all mocked behavior on this class though. If you want to remock only some methods, then you have to create the mock from scratch.
I ended using myself this pattern to mock a bunch of methods of a class providing configurations.
In a #Before method I setup a bunch of stubs for a mocked object that provide a correct configuration for each test. Afterwards, in each test it was extremely convenient to only override one of those stubs to provide a different configuration and test a different error case.
I think the response from Hari Menon is correct but it somehow defeats the purpose explained in the question. If the mock is reset, all the stubs would need to be added again, making this pattern very confusing (it would be better to not use any overriding than using reset in this case, the code would be way more straightforward).
The comments added to the question provide indeed an indirect answer on how to achieve this, and why it works, but it took me a bit to get it working.
In spite of one of the comments, I made everything work by using in my #Before fixture when().thenReturn() and overriding the concrete stub with doReturn().when()
Example:
public class WorkerTest {
private ConfigProvider mockedConfigProvider = mock(ConfigProvider.class);
#Before
public void setup() {
// Setup stubs with a correct config
when(mockedConfigProvider.getValue("property1")).thenReturn("value1");
when(mockedConfigProvider.getValue("property2")).thenReturn("value2");
when(mockedConfigProvider.getValue("property3")).thenReturn("value3");
when(mockedConfigProvider.getValue("property4")).thenReturn("value4");
}
#Test
public void test_GoodConfig(){
// The config object gets injected in the test worker
Worker testWorker = new Worker(mockedConfigProvider);
// testWorker.execute() returns true if everything went well
assertTrue(testWorker.execute());
}
#Test
public void test_BadConfigProp1(){
// Test now with a broken 'property1', overriding that stub.
doReturn(null).when(mockedConfigProvider).getValue("property1");
Worker testWorker = new Worker(mockedConfigProvider);
// testWorker.execute() returns false if there is a problem.
assertFalse(testWorker.execute());
}
#Test
public void test_BadConfigProp2(){
// This test needs to only override the result of property2
doReturn("crazy result").when(mockedConfigProvider).getValue("property2");
...
}

When you mock a class in mockito framework, do you stand up actual mock class manually?

I am fairly new to mockito framework. I've been reading upon multiple tutorials in regards to it. One of them I was following is this: https://www.tutorialspoint.com/mockito/mockito_first_application.htm
There is a statement creating a mock of Stock Service.
In this example, we've created a mock of Stock Service to get the dummy price of some stocks
My question is Stock Service is a real service class or mock service class you have to manually stand up for mimicking the real service class. I am a bit confused. Having basic understanding of junit framework. What I had practiced before was if there is a service class Foo then I used actual class that provides all the exposed methods.
public class Foo {
public Foo() { } // construtor
public String returnAddress(String userId) {
// ...
return dataAccesobj.getAddress(userId);
}
}
Calling foo.returnAddress(..) in unit test if I remember right.
The reason I am asking this question is while I was working with mockitoto create a test method for a class, I ran into a unique(?) challenge.
I started with a real service class which depends on its super class constructor to return its instance. The challenge I ran into was this super class constructor initiates DB connection and loading/parsing properties files which I do not need for my test. I was thinking about how to prevent DB connection and loading/reading prop files....
I thought I read from one of mockito tutorials you can isolate testing without having such services. I tried with #Mock and #Spy (not fully understanding well still what they are for..) but it didn't make a difference for output (maybe I misused those annotations).
So what I did was actually creating fake/mock class out of real service class (e.g. Foo) by simply copying it and renamed it as FooMock and put it in src/test/java folder in where unit test class is running from. I kept the mock class exactly same as the real service class except taking out unwanted logic such as db connection or loading/reading prop file for env specific. By doing that I was able to test one of exposed methods that read ldap directory...
I am sorry I got digressed but hope my point is clear at this point. I am not sure the way I handled this situation is right or wrong. I'd appreciate experienced engineers would clarify the way I handled the matter is acceptable in mockito way or not. If not, then plz advise me best way to handle it.
With Mockito,
a mock is an implementation of a wrapper class.
The mock object "wraps" the target of the mock
(the service in your example)
and allows you to define functionality of each method.
There are two mocked functionality options with Mockito;
call the wrapped method and don't call the wrapped method.
I don't know when it would make sense to call the wrapped method,
so I always use don't call the wrapped method.
After you create the mock,
use the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) method to mock functionality.
Edit: some more info.
I will assume that you are using junit v4.
The details of this will differ based on the the junit major release number,
but the actual work will be the same.
Use annotations to define your Mock objects (#Mock),
except in a few special cases.
This will create mocks of non-final classes,
abstract classes,
and interfaces.
Create a "before-test" method using the #Before annotation;
I traditionally name this method preTestSetup,
but the actual name does not matter.
Call MockitoAnnotations.initMocks(this) as the first line of code
in the "before-test" method.
This will find the #Mock annotations and instantiate a mock for each.
Use the ReflectionTestUtils.setField method to inject the mocks into your object (assuming that you don't have setter methods,
which I traditionally don't like).
Define the mocked functionality of each method using the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) technique.
Here is some example code
(caveat:
this should be fully functional,
but I did not compile it):
public interface MyService
{
String blammy(SomeParameter parameter);
}
public class UsesMyService
{
#Autowired
private MyService myService;
public String kapow(final SomeParameter parameter)
{
return myService.blammy(parameter);
}
}
public class UnitTestUsesMyService
{
private UsesMyService classToTest;
#Mock
private MyService mockMyService;
#Mock
private SomeParameter mockSomeParameter;
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new UsesMyService();
doReturn("Blam").when(mockMyService).blammy(mockSomeParameter);
ReflectionTestUtils.setField(
classToTest,
"myService",
mockMyService);
}
#Test
public void kapow_allGood_success()
{
final String actualResult;
actualResult = classToTest.kapow(mockSomeParameter);
assertNotNull(actualResult); // Not strictly necessary.
assertEquals(
"Blam",
actualResult);
}
}

How to create method that could be used only for tests

Are the any ways to create method/contractor that could be used only in Junit ( test purpose only ) ?
Maybe there is an annotation?
For methods that are only used for testing... why not make them part of the actual test-code? At least in build-systems such as Maven, test code is not included in packaged jars, and is only distributed as part of the sources. In that sense, it cannot be called from normal classes, since it is simply not included in the final .jar (or .war).
I very frequently write such methods to make my test-code more maintainable.
To clarify:
src/
main/
java/
my/package/
MyClass.java <-- leave necessary protected accessors here
test/
java/
my/package/
MyClassTest.java <-- implement test-code here
And in MyClassTest...
public class MyClassTest {
...
private static Foo doSomethingCoolButTesty(MyClass instance) {
// access protected or package-private MyClass code here
}
}
MyClassTest.doSomethingCoolButTesty will be kept separate from the main code, and will obviously only be available to test code. Yes, it is somewhat uglier than including it as a method of the main code, but I find a fair price to pay.
For what purpose do you need this method?
(J)UnitTests should verify the behavior of the class by using its public interface. No "special" method in the tested code should be used in unit tests.
But Unittests should replace the dependencies of the tested code with test doubles (aka fakes and mocks). The preferred way to provide those test doubles is dependency injection (DI).
Sometimes its to much effort to introduce DI to your code. In that case it is acceptable to introduce low visibility getter methods as a seam where the dependency can be replaced by the mock.
class CodeUnderTest{
private final SomeOtherClass dependency = new SomeOtherClass();
SomeOtherClass getDependency(){ // package private getter
return dependency;
}
public void doSomething(){
dependency.expectedMethodCalled();
}
}
class TestInSamePackage{
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Mock
private SomeOtherClass testDouble;
#Spy
private CodeUnderTest cut;
#Before
public void setup(){
doReturn(testDouble).when(cut).getDependency();
}
#Test
public void shouldDoSomething() {
// configure testDouble
cut.doSomething();
verify(testDouble).expectedMethodCalled();
}
}
There is nothing that would prevent to call methods "outside" of a junit test case.
My pragmatic answer: make the method package protected and add a simple comment like "unit test only" as javadoc. And educate your team to honor such statements.
And ideally: design your production code in a way that does not require such "tricks" in order to make it testable!
Given the comments on the question: it might be technically possible to somehow acquire stack trace information; to then search for the presence of #Test annotations on the corresponding methods. But that seems to be absolute overkill - and it would mean to add even more "test only" code into the production code.
And it would also be the wrong approach - as it tries to solve a "social" problem using technical means: if you don't want that people are calling a certain method - then make sure they understand that.

Mockito Mock and Spy in SpringBoot App

I have read quite a few articles/blog/StackOverflow questions, but the confusion regarding Mockito mock and spy still remains. So, I started trying implementing them in a small Spring Boot app. My app has a ProductRepository extending CrudRepository.
Currently I'm testing the repository by mocking ProductRepository as follows
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {RepositoryConfiguration.class})
public class ProductRepositoryMockTest {
#Mock
private ProductRepository productRepository;
#Mock
private Product product;
#Test
public void testMockCreation(){
assertNotNull(product);
assertNotNull(productRepository);
}
#Test
public void testSaveProduct() {
assertThat(product.getId(), is(equalTo(0)));
when(productRepository.save(product)).thenReturn(product);
productRepository.save(product);
//Obviously this will fail as product is not saved to db and hence
//#GeneratedValue won't come to play
//assertThat(product.getId() , is(not(0)));
}
#Test
public void testFindProductById() {
when(productRepository.findOne(product.getId())).thenReturn(product);
assertNotNull(productRepository.findOne(product.getId()));
assertEquals(product, productRepository.findOne(product.getId()));
}
}
The test passes. Is this the right way? I also want to understand how to use #Spy here and Why should I need it? Any specific scenarios related to this is most welcome.
Thanks in advance.
I have taken a look at your tests and there are few things to keep in mind (this is based on my experience so the final call is up to you):
1) Hamcrest - If that is possible i would strongly recommend using Hamcrest for your assert implementations.
First of all it is much more versatile and feature rich than the standard junit assertions.
Second of all you may one day have the need (as i did on one of my projects) to switch from junit to testng for examle.
Having all your assertions based on a xunit-neutral implementation, the switch will not be so painful.
2) Assertions - Instead of assertNull, assertEquals go for the hamcrest's assertThat(String description, T value, Mathcer<T> matcher);
Thanks to that you will get clear error messages when a test breaks.
3) Small tests - In your Repository test.. do not put all the cases in one test.
Try to create many small and simple tests for cases like: findOne.. count.. findAll etc.
Again it will be easier to find the problem when a small test like that breaks.
And if more cases will come you wont end up with a 200+ lines of a test case which is unacceptable
4) Naming - Do not name your tests as.. testXYZ.
It is obvious that these are test methods.
I would recommend using the BDD way of naming: shouldX_whenY_givenZ.
F.e. shouldReturnZeroCount_givenNoEntitiesInTheDatabase
5) Structure - Try to split each of your test implementation in three explicit sections, including comments for best result:
public void should..() throws Exception{
// Arrange
// when().then()
// mock()
// Act
// classUnderTest.process()
// Assert
// assertThat(..)
}
6) Do not split your test classes between Mock / Spy test. HAve one ImplTest.
7) Never mock a class which you are testing. In the worst case scenario use Spy if you have to mock some of the methods of the class under test.
The point of mocking is to isolate the implementation in the class under test, so that only that classes logic is invoked during the test.
Mock only dependencies of the class.

Categories