Not able to get values from the yaml file using Mock in Groovy test case - unit-testing

I'm writing a unit test case for my functionality using Groovy. But, however I'm not able to configure the values that are available in the class. The values are configured in my yaml file.
Here is my code
class UpdateServiceImplTest extends Specification {
DataSourceRestTemplateConfig dataSourceRestTemplateConfig
def setup() {
dataSourceRestTemplateConfig= Mock(DataSourceRestTemplateConfig )
}
}
This DataSourceRestTemplateConfig class is using some properties, which is coming as null while executing the test
public class DataSourceRestTemplateConfig {
#Autowired
RestTemplate restTemplate;
#Value("${datasource.auth.username}")
private String userNameNew;
#Value("${datasource.auth.password}")
private String passwordNew;
// Method to call DB here
}
The above values are coming as null when I evaluate the expression. Are there any other configurations am I missing?
Any ideas would be greatly helpful to me.

Related

How to test predicate in an unit test?

I have an Apache Camel application, which uses a Choice with a Predicate. How can I test the predicate without an integration test?
Code
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public EndpointRouteBuilder route() {
return new EndpointRouteBuilder() {
#Override
public void configure() throws Exception {
from(file("d:/tmp/camel/"))
.choice()
.when(jsonpath("$[?(#.status == 0)]"))
.log("ok")
.otherwise()
.log("not ok");
}
};
}
}
Research
I read Test JUnit5, but it looks like an integration test. However, I don't want to test a full route.
I read Test Spring JUnit5, but it is an integration test.
Question
How can I extract the predicate jsonpath("$[?(#.status == 0)]") and test it isolated in an unit test with JUnit 5?
Might be hard to accomplish this without a CamelContext. I'd probably approach this with Camel's excellent mocking and stubbing utilities. But if you really just want to isolate the jsonpath expression, you could try something like this:
JsonPathExpression exp = new JsonPathExpression("$[?(#.status == 0)]");
Exchange exchange = new DefaultExchange(context);
final Predicate predicate = exp.createPredicate(context);
exchange.getIn().setBody("{ \"status\": 0 }");
final boolean matches = predicate.matches(exchange);
assertTrue(matches);
Note that you'll still need a CamelContext for this. Typically you'd get it by having the test class extend CamelTestSupport, or if you're in a spring environment, spring can autowire it: #Autowired CamelContext camelContext;
Edit: If you just want to test the JsonPath expression outside of Camel:
String jsonPath = "$[?(#.status == 0)]";
String json = "{ \"status\": 0 }";
DocumentContext jsonContext = JsonPath.parse(json);
JSONArray result = jsonContext.read(jsonPath);
assertEquals(1, result.size());
My opinion (you'll probably get 100 more ;-)
Separate that route into another class by itself that can be loaded into the Spring context later.
Use CamelTestSupport to load just Camel (not Spring) in JUnit.
Use Camel "advice" to change "from" to a direct, or create a file (in your test) to exercise the test case you want (once with each branch of the choice.
Again with "advice" change the log to mocks - then after running the file/message you want check to see if the correct mock got a message and the other did not.

cannot stub ReactiveMongoRepository using Mockito.when

I'm new to reactive programming. I want to write some test cases for a reactive mongo repository. I tried to stub some query methods and use step-verifier to check the response, but my test gets fail .
ItemReactiveRepository.java
public interface ItemReactiveRepository extends ReactiveMongoRepository<Item, String> {
Mono<Item> findByDescription(String description);
}
Item.java
#Document
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Item {
#Id
private String id;
private String description;
private Double price;
}
ItemReactiveRepositoryTest.java
#DataMongoTest
#RunWith(SpringRunner.class)
public class ItemReactiveRepositoryTest {
#Autowired
private ItemReactiveRepository itemReactiveRepository;
#Test
public void findById() {
Item itemForTest = new Item("ABC", "Samsung TV", 405.0);
Mockito.when(itemReactiveRepository.findById("ABC")).thenReturn(Mono.just(itemForTest));
StepVerifier.create(itemReactiveRepository.findById("ABC"))
.expectSubscription()
.expectNextMatches(item -> item.getPrice() == 405.0)
.verifyComplete();
}
}
Error I receive when running test
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object.
Are there any limitations to use stubbing when test reactive streams? Or any other standard mechanism to test above scenarios?
Instead of using #Autowired you have to prepare mock for Repository from import org.mockito.Mock;
#Mock
ItemReactiveRepository itemReactiveRepository;
As #Thomas has mentioned, you are not mocking instead using the actual MongoDB using DataMongoTest instead you have to get rid of this and just mock the methods and test your service layer. Autowired is expecting all default configuration and a bean which is prepared by the container for you to use which is not the case, you have to mock and use.
ItemReactiveRepository itemReactiveRepository=org.mockito.Mockito.mock(ItemReactiveRepository.class);
This worked for me.

Spring boot Unit test with #WebMvcTest - execution doesn't enter service layer from controller and returns null without error

I am writing unit test for a controller of my spring boot application.
I have typical MVC classes: ObjectSchemaController, ObjectSchemaService and ObjectSchemaDao.
I have written unit test with #WebMvcTest and mocked my service and dao class with #MockBean. (following this guide: https://www.baeldung.com/spring-boot-testing)
Below is my unit test :
#RunWith(SpringRunner.class)
#WebMvcTest(ObjectSchemaController.class)
public class ObjectSchemaControllerTest2 {
#Autowired
private MockMvc mvc;
#MockBean
private ObjectSchemaService service;
#MockBean
private ObjectSchemaDao dao;
#Autowired
ObjectMapper objectMapper;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
Mockito.when(service.createSchema(objectSchema))
.thenReturn(objectSchema);
Mockito.when(dao.createSchema(objectSchema)).thenReturn(objectSchema);
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/")
.contentType("application/json")
.content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}
}
below is my service class:
#Service
public class ObjectSchemaService {
#Autowired
ObjectSchemaDao objectSchemaDao;
public ObjectSchema createSchema(#Valid ObjectSchema objectSchema)throws Exception {
return objectSchemaDao.createSchema(objectSchema);
}
}
The issue I am facing with Unit test is, the service layer doesn't get executed and returns null value.
When I debug, I can see execution reaching in my controller class and ObjectSchemaService as being mockito-mocked in the controller. But the execution never goes in service layer and the value returned by service method is null.
I have referenced other guides- they are doing similar steps. But its not working for me. What am I missing here?
I have also seen this post with similar issue.
Unit Test POST with #WebMvcTest - #MockBean Service returns null
I made sure the input objects to both my actual controller and the one I am passing in unit case are instances of same class.
You are mocking the ObjectSchemaService but no behaviour is expected.
You need to setup the behaviour for the services that are mocked. So depending on the method signature and result somethink like.
Mockito.when(service.createSchema(Mockito.any(ObjectSchema.class)).thenReturn(objectSchema);
At the moment the ObjectSchemaService mock just returns a default value which is null in your case.
In order to be transparent and unobtrusive all Mockito mocks by default return 'nice' values. For example: zeros, falseys, empty collections or nulls.
If you update your answer with details for ObjectSchemaService I could also update my answer.
You mock ObjectSchemaService so you need to tell the service how mock the values from the service when a method is called. If you don't mock the values of the service Mockito don't know what they have to return always give you null. Not need to mock ObjectSchemaDao in this test.
Note: I use Lombok in the code as ObjectSchema.builder() to return the object with the Id when is stored in the database, you can use a constructor. Assuming the service return the object.
The code looks like this:
import static org.mockito.BDDMockito.given;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
given(service.createSchema(objectSchema)).willReturn(
ObjectSchema.builder()
.id(1)
.someKey("Some Val")
.build());
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/").contentType("application/json").content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}

Is it possible to Mock and ignore properties

I'm changing our identity strategy and we're using an ID that is generated before the Entity is written to the database. This change is causing some of our tests to fail due to the way we're mocking some service calls.
TimeLog timeLog = buildTimeLog('123456', mockEmployeeId);
TimeLog mockTimeLog = buildTimeLog('123456', mockEmployeeId);
when(this.timeLogService.save(mockTimeLog)).thenReturn(timeLog);
When the test makes the call to the Controller, the bound entity in the Controller gets a different ID than the mock that is expected because the Entity generates the ID. Whereas before, the database generated the ID so the mocks worked.
If there is a way to tell Mockito to ignore a property in the expectation? That would solve the problem and the test would still be valid. Otherwise, other approaches are welcome.
You can't tell mockito to ignore a property in an expectation because it's using the java "equals" method... You can define an equals method in TimeLog that igonres ID but I suspect that won't give you what you want. The other approach is, instead of trying to tell mockito what not to verify, define explicitly what it is to verify using a hamcrest matcher. Define a hamcrest matcher which just matches the fields you want to verify i.e. all fields other than ID. So something like:
private class TimeLogMatcher extends TypeSafeMatcher<TimeLog> {
private final EmployeeId employeeId;
public TimeLogMatcher(EmployeeId employeeId) {
this.employeeId = employeeId;
}
#Override
public void describeTo(Description description) {
description.appendText("TimeLog with employeeId=" + employeeId);
}
#Override
public boolean matchesSafely(TimeLog item) {
return employeeId.equals(item.getEmployeeId());
}
}
And then instead of calling whatever your "buildTimeLog" method is doing call into the mockito Matchers class like:
TimeLog timeLog = Matchers.argThat(new TimeLogMatcher(mockEmployeeId));
Or alternatively you could always use an Answer object:
when(this.timeLogService.save(any(TimeLog.class)).thenAnswer(new Answer<TimeLog> {
public TimeLog answer(InvocationOnMock invocation) throws Throwable {
TimeLog receivedTimeLog = invocation.getArgumentAt(0, TimeLog.class);
assertThat(receivedTimeLog.getEmployeeId(), equalTo(mockEmployeeId));
return timeLog;
}
});
Does that all make sense?

Unit test custom doctrine repository

I have a custom entity repository. For example, it looks like this:
namespace Foo\Repository;
use Doctrine\ORM\EntityRepository;
class Article extends EntityRepository
{
public function findRecent($limit)
{
$qb = $this->createQueryBuilder('a');
$qb->andWhere('a.publishDate IS NOT NULL')
->orderBy('a.publishDate', 'DESC')
->setMaxResults($limit);
return $qb->getQuery()->getResult();
}
}
I want to test in this case:
There is an ORDER BY in "recent"
There is a limit
The entity must have a publish date
I do not want to validate the SQL output of the query builder, since Doctrine can change the SQL between different versions. That will break my unit test. Therefore, my idea was this:
Create a mock of my repository
Create a mock of the query builder
Make sure $this->createQueryBuilder('a') returns the mocked query builder
Test for method calls on the query builder
In code:
namespace FooTest\Repository;
use PHPUnit_Framework_TestCase as TestCase;
class ArticleRepositoryTest extends TestCase
{
protected $qb;
protected $repository;
public function setUp()
{
$this->qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
->disableOriginalConstructor()
->getMock();
$this->repository = $this->getMockBuilder('Foo\Repository\Article')
->disableOriginalConstructor()
->getMock();
$this->repository->expects($this->once())
->method('createQueryBuilder')
->with($this->equalTo('a'))
->will($this->returnValue($this->qb));
}
public function testFindRecentLimitsToGivenLimit()
{
$limit = '1';
$this->qb->expects($this->any())
->method('setMaxResults')
->with($this->equalTo($limit));
$this->repository->findRecent($limit);
}
public function testFindRecentOrdersByPublishDate()
{
$this->qb->expects($this->any())
->method('andWhere')
->with($this->equalTo('a.publishDate'), $this->equalTo('DESC'));
$this->repository->findRecent(1);
}
}
This findRecent() call however never calls createQueryBuilder internally. PhpUnit points out:
FooTest\Repository\ArticleRepositoryTest::testFindRecentLimitsToGivenLimit
Expectation failed for method name is equal to when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
I think I did something wrong in creating the repository mock. How can I make sure this approach works? Or if there is a better alternative, what is that?
It looks to me like you are mocking the Repository you are trying to test, so findRecent() is indeed mocked and will return null.
You should be able to use the real repository instance.
The solution I found to testing subclassed repositories is to add a call to setMethodsExcept() when building the mock.
So you would modify your code within setUp() above like so:
$this->repository = $this->getMockBuilder('Foo\Repository\Article')
->disableOriginalConstructor()
->setMethodsExcept([
// Insert any overridden/implemented functions here, in your case:
'findRecent',
])
->getMock();