A little guidance on jmock - java

I have tried the documentation on the jmock site and I'm simply lost. It appears that it's great documentation for someone that already knows how to use it. I'm not one of those. I'm looking for one of those. :)
I have a services layer that all front ends to my app communicate with. The services layer uses the DAOs to communicate with the database and return my model objects. I'd like to use Jmock for those DAOs so that there's no trips to a database.
So, I have PersonServiceImpl that implements PersonService and PersonHibernateDAO that implements PersonDAO in hibernate. Example person service follows.
public class PersonServiceImpl implements PersonService{
public void changeName(int personId, String firstName, String lastName){
person = getPersonDAO.getPerson(int personId);
person.setFirstName(firstName);
person.setLastName(lastName);
getPersonDAO.update(person);
}
}
How do I use jmock to unit test my person service?

I think this is what should work.
public class MyTestClass{
Mockery context = new Mockery();
private PersonServiceImpl personService;
private PersonDAO dao;
private Person person;
#Before
public void setup(){
person = new Person();
// set up mock to return person object
dao = context.mock(PersonDAO.class);
oneOf (dao).getPerson(5); will(returnValue(person));
// create class under test with mock
personService = new PersonServiceImpl(dao);
}
#Test
public void myTest(){
// expectations
context.checking(new Expectations() {{
oneOf (dao).update(person);
}});
// test
psersonService.changeName(....);
// verify
context.assertIsSatisfied();
}
}
Personally, I think mockito is easier...
public class MyTestClass{
private PersonServiceImpl personService;
private PersonDAO dao;
private Person person;
private ArgumentCaptor<Person> argCaptor;
#Before
public void setup(){
person = new Person();
argCaptor = ArgumentCaptor.forClass(Person.class);
// set up mock to return person object
dao = Mockito.mock(PersonDAO.class);
when(dao.getPerson(5).thenReturn(person);
// create class under test with mock
personService = new PersonServiceImpl(dao);
}
#Test
public void myTest(){
// test
psersonService.changeName(....);
// verify
verify(dao).update(argCaptor.capture());
Person passedPerson = argCaptor.getValue();
assertThat(passedPerson.getFirstName(), equalTo(...));
}
}

Related

How to use Mockito to populate POJO

I have a POJO class:
#Data #Document
public class RoomPreferences{
private TypeEnum roomType;
private BigDecimal minLen;
private BigDecimal maxLen;
private List<BigDecimal> defaultPrices;
}
I want to populate a RoomPreferences object at test and I am using Mockito, but my RoomPreferences object's fields are always null.
public class TestingClass {
#Mock private RoomPreferences roomPreferences;
#InjectMocks public RoomServiceImpl roomService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
...
}
}
What I read out of this testing class:
public class TestingClass {
#Mock private RoomPreferences roomPreferences;
#InjectMocks public RoomServiceImpl roomService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
...
}
}
is that roomService of type RoomServiceImpl has an attribute of type RoomPreferences. And this attribute will be injected with the mocked object "roomPreferences".
The mocked object won't be populated with any value of the real class.
What you do is define what the mock should do when a method (as in the real class) is called on it:
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
If you wan to assing a value to a property then don't mock the class and use the real class instead.
I am guessing that the problem you are facing is setting the RoomPreferences attribute in the roomService object. If that is the case you should add that class to the question.

How to properly publish DDD domain events with spring?

I am trying to implement domain driven design in my project.
Here is my base Aggregate class:
public abstract class UUIDAggregate {
private final DomainEventPublisher domainEventPublisher;
protected void publish(DomainEvent domainEvent) {
domainEventPublisher.publish(domainEvent);
}
}
Let's say we have UserAccount aggregate:
public class UserAccount extends UUIDAggregate {
private String email;
private String username;
private String password;
private String firstName;
private String lastName;
public void update() {
publish(new DomainEventImpl());
}
}
Here is my DomainEventPublisher:
public interface DomainEventPublisher {
void publish(DomainEvent event);
}
Here is DomainEventPublisherImpl:
#Component
public class DomainEventPublisherImpl implements DomainEventPublisher{
#Autowired
private ApplicationEventPublisher publisher;
public void publish(DomainEvent event){
publisher.publishEvent(event);
}
}
Now, this seems like a good idea, the domain is separated from implementation but this does not work. DomainEventPublisher cannot be Autowired because UUIDAggregate is not a #Component or #Bean . One solution would be to create DomainService and publish event there but that seems like leaking of domain to domain service and if I go that way, I am going to anemic model. Also what I can do is to pass DomainEventPublisher as a parameter to every aggregate but that also does not seems like a good idea.
One idea would be to have a factory for domain objects:
#Component
class UserAccountFactoryImpl implements UserAccountFactory {
#Autowired
private DomainEventPublisher publisher;
#Override
public UserAccount newUserAccount(String email, String username, ...) {
return new UserAccount(email, username, ..., publisher);
}
}
Then your code creating a domain object is "publisher-free":
UserAccount userAccount = factory.newUserAccount("john#example.com", ...);
Or you might slightly change the design of the event-publishing:
public abstract class UUIDAggregate {
private final List<DomainEvent> domainEvents = new ArrayList<>();
protected void publish(DomainEvent domainEvent) {
domainEvents.add(domainEvent);
}
public List<DomainEvent> domainEvents() {
return Collections.unmodifiableList(domainEvents);
}
}
#Component
class UserAccountServiceImpl implements UserAccountService {
#Autowired
private DomainEventPublisher publisher;
#Override
public void updateUserAccount(UserAccount userAccount) {
userAccount.update();
userAccount.domainEvents().forEach(publisher::publishEvent);
}
}
This is different from your proposal: the service publishes the events, but doesn't create then - the logic stays in the domain object.
Further, you can change your publisher to minimize the boiler-plate code:
public interface DomainEventPublisher {
void publish(UUIDAggregate aggregate);
}
Vaughn Vernon in his book IDDD just uses singleton like this:
DomainEventPublisher.instance().register(...);
DomainEventPublisher.instance().publish(...);
I know this approach doesn't use spring injection but it's much simplier than passing publisher to every aggregate and not that hard to test.

Mock Hibernate #Entity with preset data

Hibernate makes its magic with reflection and init #Entity with data when it fetches data from DB. So I don't need to add setters or a constructor to init my data.
#Entity
#Table(name = "products")
public class Product implements Serializable {
private integer id;
private String name;
}
#Repository
public interface ProductsRepository extends JpaRepository<Product, String> {
#Query("FROM #{#entityName} p where p.id = :id")
Product findById(integer id);
}
Fun starts when you make a unit test for some Service that deals with JpaRepository. I want to mock the repo to return mocked Product with test data
#Service
public class MyAwesomeService {
#Autowired
private ProductsRepository productsRepository;
public void returnProductName(Long productId) {
Product product = productRepository.findById(productCode);
return product.getName();
}
}
// The test will look like
#ExtendWith(SpringExtension.class)
public class ProductsDeliveryTest {
#InjectMocks
private MyAwesomeService myAwesomeService;
#Mock
private ProductsRepository productsRepository;
#Test
public void test() {
String productId = 1L;
Product product = new Product() // here I need to init Product with data
doReturn(productBookingFields)
.when(productsRepository)
.findById(productId);
String name = myAwesomeService.returnProductName(productId);
assertThat(name).isEqualTo("Test Product");
}
}
So I could
add a constructor for the Product where I will init fields
or make Product as JavaBean and use setters to init my data
The problem is - I need them only for the tests and it doesn't look like a good idea when I change my code to make my tests work.
Is there a more elegant way how can I mock Entity with preset data?
You could simply mock the entity.
#Test
public void test() {
String productName = "w00t!";
long productId = 1L;
Product product = mock(Product.class);
doReturn(productName).when(product).getName();
doReturn(product)
.when(productsRepository)
.findById(productId);
String name = myAwesomeService.returnProductName(productId);
assertThat(name).isEqualTo(productName);
}
It is a bit strange though to see your entity with only the default constructor, and no setters. Such an entity could only be used as a read only entity. Your application code could never insert a new Product or update the fields of an existing one.
This may be helpful...
#Mock Product productMock;
#Mock ProductRepository productRepoMock;
#Test
public void validateEntityMock() {
given(productMock.getName()).willReturn("name");
given(productRepoMock.findOne(anyInt())).willReturn(productMock);
// assert the results...
}

Initializing repository with Spring Data JPA

image attached after answer from Lorelorelore
basically, I tried to use hibernate in my project, but it became pretty chaotic, so I decided to test it again, so I created a new spring project. I have a POJO - Car class and a CarRepository. As far as I understand, it should use basic methods from the CRUD repository - but, when I want to save a object (or use any other method) it just doesn't work (it shows that I should initialize variable "carRepository"). Could you please help me with that? Thanks in advance
//CARTESTER CLASS
public class CarTester {
public static void main(String[] args) {
#Autowired
CarRepository carRepository;
//I want to use a method from crudrepository here
carRepository.save(new Car(1, "AAA", "BBB", 1111));
carRepository.findAll();
}
}
//CAR CLASS
#Table(name = "CARS")
#Entity
public class Car {
#Id
private Integer id;
private String brand;
private String model;
private int manufactureYear;
//constructors, getters, setters, toString()
//CARREPOSITORY CLASS
#Repository
public interface CarRepository extends CrudRepository<Car, Integer> {
}
Your test class should look like this:
#RunWith(SpringRunner.class)
#DataJPATest
public class CarTester {
#Autowired
CarRepository carRepository;
#Test
public void test() {
carRepository.save(new Car(1, "AAA", "BBB", 1111));
carRepository.findAll();
}
}

Spring inject dependency for constructors

I'm planning to create my objects in my Spring MVC using the below setup but How can I inject values to my MyService ie; instantiate the object with default value...
public class MyController {
private MyService myService;
#Autowired
public void setMyService(MyService aService) { // autowired by Spring
this.myService = aService;
}
#RequestMapping("/blah")
public String someAction()
{
// do something here
myService.foo();
return "someView";
}
}
MyService
class Myservice(){
String servicename;
public Myservice(servicename){
this.servicename = servicename;
}
}
Without Spring
MyService first = new MyService("firstservice");
MyService second = new MyService("secondservice");
Just declare your constructor with #Autowired to mark it as the constructor to use and its parameter with #Value to indicate the value to use.
#Autowired
public Myservice(#Value("example") String servicename){
Or use a placeholder
#Autowired
public Myservice(#Value("${placeholder.key}") String servicename){
Firstly, your exam are wrong on using Spring DI. To inject Myservice type to another You should declare MyService as a interface instead:
interface Myservice(){
public void foo();
}
After that, declare an implementation of this interface (again, use Spring DI to inject String type):
class BarService() implements Myservice{
String servicename;
#Autowired
public Myservice(#Value("servicename") String servicename){
this.servicename = servicename;
}
public void foo(){
}
}

Categories