I have class:
#Service
public class A {
#Value("${a.b.c}")
private String abc;
public void foo() {
sout(abc);
}
}
I Have test class:
#SpringBootTest
#SpringBootConfiguration
#RunWith(SpringRunner.class)
#TestPropertySource(locations = "classpath:application.yml")
public class TestA {
#Value("${a.b.c}")
private String abc;
#InjectMocks
private A a;
#Test
public void testFoo() {
this.a.foo();
}
}
When I debugging the test method testFoo(),
I see that variable abc is read from the application.yml file.
But,
inside the foo() method,
I see that the variable abc is null.
How can I set variable abc such that it is available in method foo() when I trying to test this method?
Step one is to answer this question: Am I unit testing the code in my class or am I integration testing the combination of Spring and some collection of code that includes my class?
If you are unit testing your code,
then it is not necessary to have Spring do its thing.
Instead,
you only need to instantiate your class,
set the values that Spring would have set for you,
execute the method you are testing,
then verify that your method executed correctly.
Here is your example unit test rewritten as I suggested:
public class TestA
{
private static final String VALUE_ABC = "VALUE_ABC";
private A classToTest;
#Test
public void testFoo()
{
classToTest.foo();
}
#Before
public void preTestSetup()
{
classToTest = new A();
ReflectionTestUtils.setField(
classToTest,
"abc",
VALUE_ABC)
}
}
Some Notes:
ReflectionTestUtils is part of Spring-test.
You don't need to use #InjectMocks because you have no mocks to inject.
I don't know what sout is, so I excluded it from the test. You should verify that the sout method was called with the correct value (in this case VALUE_ABC).
If you are just unit testing your code, you don't need Spring, which means that you don't need to use the #RunWith annotation.
You can try to overide the properties like that:
#TestPropertySource(locations = "location.properties",
properties = "a.b.c=123")
Example taken from here
Related
I have a dependency in the Spring Boot which is called from my class. This dependency makes a call with a newly instantiated builder pattern class as an argument. I need to know if it is possible to verify if this single builder class was constructed with certain values when the dependency call is made, e.g.:
public class MyClass {
#Autowired
private MyDep myDep;
public void callMyDepService() {
myDep.serviceCall(new MyBuilder().paramOne("One").paramTwo("Two").build());
}
}
As you can see, a new MyBuilder is instantiated every time, so I can't just use Mockito's eq() to match the arguments' value.
I would like to make sure callMyDepService calls myDep.serviceCall with certain parameter values.
Using a captor seems to be the easiest way to do that.
Something like this, where SomeClass is the class your MyBuilder builds.
#ExtendWith(MockitoExtension.class)
public class CaptureTest {
#InjectMocks
MyClass classUnderTest;
#Mock
MyDep myDep;
#Test
public void test() {
classUnderTest.callMyDepService();
Captor<SomeClass> captor = ArgumentCaptor.forClass(SomeClass.class);
Mockito.verify(myDep).serviceCall(captor.capture());
SomeClass parameter = captor.getValue();
// do assertions
}
}
I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1.
The class has some fields annotated with #Mock, as well as some fields annotated with #InjectMocks.
The attribute that is annotated with #InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock.
The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticClass.class })
public class TestClass {
#Mock
private SomeClass attribute1;
#InjectMocks
private SomeOtherClass attribute2;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(StaticClass.class);
when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
}
#Test
public void test1() {
assertEquals(attribute2.method1(), value1);
}
#Test
public void test2() {
assertEquals(attribute2.method2(), value2);
}
}
public class SomeOtherClass {
private SomeClass attribute;
public SomeOtherClass() {
SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
value.someOtherMethod();
}
}
As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock.
The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).
As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.
For some reason it works the first time - there exists
an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).
Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.
private SomeClass attribute;
private SomeOtherClass testClass;
#Before
public void setUp() {
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());
attribute = Mockito.mock(SomeClass.class);
testClass = new SomeOtherClass();
// assign mock manually
testClass.attribute = attribute;
}
The prefered way would be to supply the attribute using the constructor of SomeOtherClass, however since you seem to use a empty constructor
you will have to set the value from the outside. If the attribute instance is not accessible you might be forced to use reflections.
The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.
Some people even say you should not have any logic inside of a constructor.
We have a Spring 5 application using JUnit 4 as our test harness (w/ SpringRunner). We're experiencing an issue where a private helper method that's not marked with a #Test annotation is being run as a test. This happens in both IntelliJ and Maven.
The method signature is:
private Optional<TestSuiteJsonObject> createTestSuite(String name, TestType type) throws IOException, LicenseException {
And the test class itself looks like:
public class TestSuitesControllerTest extends ControllerTest
There are no annotations on either. The ControllerTest looks like:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = CompanyTestApplication.class)
#AutoConfigureMockMvc
#Ignore
public class ControllerTest {
...
}
The behavior is that these test methods are run with null arguments. We don't want them to be run at all. The rest of the methods in this class are appropriately marked with the #Test annotation.
I wondered if the fact that the word test is in the class/method name could be causing JUnit to identify it as runnable, but changing the names of both the class and method has no effect.
Adding #Ignore to the private method also has no effect!
What are we doing wrong? Did we step into an alternate dimension where test harnesses are actually testing stress responses of the engineers?
It was a silly mistake, but I'm leaving it for any future folk who find themselves in the same situation.
I had two methods with the same name. The test method:
#Test
#WithMockUser(username = "admin", roles = "ADMIN")
public void createSuite() throws Exception { ... }
And the helper method:
private static Optional<TestSuiteJsonObject> createSuite(String name, TestType type) { ... }
And we somehow glossed over this. 🤦♂️
Example:
public class myClass {
private WebService webService;
public void process(String delimitedString) {
String[] values = StringUtils.split(delimitedString, "$%");
insideMethod.setFirstName(values[0]);
insideMethod.setMiddleName(values[1]);
insideMethod.setLastName(values[2]);
insideMethod.setBirthDate(values[3]);
webService.getResponseWS(insideMethod.getFirstName,
insideMethod.getMiddleName,
insideMethod.getLastName,
insideMethod.getBirthDate);
}
}
I want to test that the right values are being set in insideMethod to make sure that the correct parameters are being passed to webService.getResponseWS()
This is in Java and I should use unit tests and Mokito.
Note: I am not testing the webService method. I need to test that the values passed to insideMethod are correct. Example "John" for name instead of "JohnSm" or "John$%".
So far I have created a test class, instantiated the class being tested and mocked the webService class.
public class TestClass {
MyClass myClass = new MyClass();
private WebService webService = mock(WebService.class);
public void processTest() {
when(webService.getResponseWS()).thenCallRealMethod();
insideMethod.process("John$%J$%Smith$%02-02-1990");
You want to use Mockito.verify().
The JavaDoc aor the Mockito Verify Cookbook lists a lot of examples.
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class TestClass {
#Mock
private WebService webService;
private MyClass myClass = new MyClass();
#Test
public void processTest() {
// inject webService mocked instance into myClass instance, either with a setter
myClass.setWebService(webService);
// or using Mockito's reflection utils if no setter is available
//Whitebox.setInternalState(myClass, "webService", webService);
// call the method to be tested
String input = "input"; // whatever your input should be for the test
myClass.process(input);
// verify webService behavior
verify(webService).getResponseWs(
"expectedInput1", "expectedInput2", "expectedInput3", "expectedInput4");
}
}
Provided you've set up Mockito and injected your mocks correctly, the following should work (although I don't have a compiler or JVM at hand to check).
verify(webService).getResponseWS("John", "J", "Smith", "02-02-1990");
I have the following scenario
interface DAO
{
String a();
String b();
String c();
}
I create a mock of this DAO interface and I feed it to something called DAOProcess. Inside DAOProcess, I have various methods calling DAO methods a, b and c.
Now each time I need to unit test a method in DAOProcess, I'll end up writing when(mockDAO.a()).thenReturn("test").
Is there anyway I can move these when(mockDAO.a()).thenReturn("test") common to all the test cases ?
If your test cases are all in one class you could make use of a method annotated with #Before, e.g.:
...
private DAO mockDAO;
#Before
public void setUp() {
mockDAO = mock(DAO.class);
when(mockDAO.a()).thenReturn("test");
...etc...
}
...
Or, if you need the behaviour over many test classes you could write a utility class to set behaviour on a Mock instance, e.g.:
public class MockDAOPrototype {
public DAO getMockWithDefaultBehaviour() {
final DAO mockDAO = mock(DAO.class);
when(mockDAO.a()).thenReturn("test");
...etc...
return mockDAO;
}
}
And then call MockDAOPrototype.getMockWithDefaultBehaviour() in your setUp method.
You can create an AbstractTestCase class that is abstract and is extended by all test cases where you need this mock. In that abstract test case, you will have the following statements.
#Ignore // just in case your runner thinks this is a JUnit test.
public abstract class AbstractTestCase
{
#Mock
private DAO mockDAO;
#Before
private void setupMocks()
{
when(mockDAO.a()).thenReturn("test")
....
}
}
In your concrete test case classes, you would
public class MyConcreteTestCase extends AbstractTestCase
{
#InjectMocks
#Autowired
private DAOProcess daoProcess;
....
}