I have a Springboot API that includes a model class Payment, a @Service class PaymentService, as well as a JPA repository, controller, and some utility classes. I have integration tests that mostly work using junit, h2 in-memory db, and RestTemplate. When I run the test to, for example, create a new payment, the @Service class runs, does the business logic, saves the new object in the in-memory database, sets a few more fields, and then returns the created object.
My test:
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
@FieldDefaults(level=AccessLevel.PRIVATE)
public class PaymentControllerCreateTest {
@LocalServerPort
int port;
String baseUrl = "http://localhost";
static RestTemplate restTemplate = null;
@BeforeAll
public static void init() {
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
}
@BeforeEach
public void setup() {
baseUrl += ":" + port + "/payment";
}
@Test
@Sql(statements="delete from payment_line_items", executionPhase=Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Sql(statements="delete from payment", executionPhase=Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testCreateBasicPayment() throws Exception {
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "token");
HttpEntity<Payment> entity = new HttpEntity<>(payment, headers);
ResponseEntity<Payment> response = restTemplate.postForEntity(baseUrl, entity, Payment.class);
assert response.getStatusCode().is2xxSuccessful();
Payment created = response.getBody();
// these assertions pass, but amount and currency code are set in the POSTed object
assert created.getCardInfo() == null;
assert created.getAmount().compareTo(payment.getAmount()) == 0;
assert created.getCurrencyCode().equals(payment.getCurrencyCode());
// these assertions fail, and the fields are either autogenerated or set in the service
assert created.getId() != null;
assert created.getTransId() != null;
}
}
Relevant bits of Payment class:
@Entity @Table(name="payment")
@JsonInclude(Include.NON_NULL)
@Data
@FieldDefaults(level=AccessLevel.PRIVATE)
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Payment {
@Id
@GeneratedValue
@JsonProperty(access=Access.READ_ONLY)
UUID id;
@JsonProperty(access=Access.READ_ONLY)
String transId;
@NotNull
@JsonSerialize(using=BigDecimalSerializer.class)
BigDecimal amount;
@NotNull
String currencyCode;
...
}
Simplified @Service class:
@Service
@NoArgsConstructor
public class PaymentService {
@Autowired
PaymentRepository repository;
public Payment createPayment(Payment payment) {
// do business logic, submit payment, etc.
payment.setTransId(tid);
payment.setCardInfo(null); // set payment info to null so it isn't included in response
return repository.saveAndFlush(payment);
}
}
I can verify that the code in the @Service class is running (via print statements and other ways related to the specific business logic). However, the returned object from restTemplate.postForEntity() is missing some fields, namely all those that are set by the @Service code and @GeneratedValue fields. Everything works as expected when running manual tests using curl. How can I get the correct object to be returned from the restTemplate.postForEntity()?
MRE for the issue: https://github.com/honreir/SO-79624582-mre
PaymentServiceas wellorg.springframework.transaction.annotation.Transactionalannotation above thecreatePaymentmethod and run the test