title: Unit testing with mongodb repositories
body: <p>I have built application that uses MongoDB and I have came across problem with testing.</p>
  
  <p>As long as I used JPA and some relational database I used some test layer which switched persistence to in-memory database (linke HSQLDB or MySQL) for test purposes. This way I was able to limit IO operations and speed up tests.
  However with MongoDB and Spring Data it is very convenient to use repositories based on interfaces extending MongoRepository.</p>
  
  <p>My question is how to deal with unit testing and functional testing when using repositories? For example I have simple class that is anotated as mongo document:</p>
  
  <pre><code>public class Company {
  
  @Id
  private String id;
  @NotEmpty
  private String name;
  private String description;
  private String website;
  private String logo;
  
  public String getName() {
      return name;
  }
  
  public void setName(String name) {
      this.name = name;
  }
  
  public String getDescription() {
      return description;
  }
  
  public void setDescription(String description) {
      this.description = description;
  }
  
  public String getWebsite() {
      return website;
  }
  
  public void setWebsite(String website) {
      this.website = website;
  }
  
  public String getLogo() {
      return logo;
  }
  
  public void setLogo(String logo) {
      this.logo = logo;
  }    
  }
  </code></pre>
  
  <p>and related repository:</p>
  
  <pre><code>@Repository
  public interface CompanyRepository extends MongoRepository&lt;Company, Serializable&gt; {
  }
  </code></pre>
  
  <p>It is used in coresponding controller:</p>
  
  <pre><code>@RestController
  public class CompanyController {
  
  private static final Logger log = LoggerFactory.getLogger(CompanyController.class);
  @Autowired
  private CompanyRepository repository;
  
  @RequestMapping(value = "/company", method = RequestMethod.POST)
  public void create(@Valid @RequestBody(required = true) Company company) {
      repository.save(company);
  }
  }
  </code></pre>
  
  <p>Finally I made two tests (however it could be one covering both tasks) that covers controller api and data format (where I mock repository to prevent from IO operations, and it works nice), and second where I want to make sure that passed object was persisted successfuly. As it cames out it is not so simple. First of all (correct me if I'm wrong) there is no in-memory mongo implementation. Secondly, I cannot verify with mockito execution of save method because of inheritance I suppose.</p>
  
  <pre><code>@ContextConfiguration(classes = Application.class)
  @WebAppConfiguration
  public class CompanyControllerNGTest extends AbstractTestNGSpringContextTests {
  
  @Mock
  private CompanyRepository repositoryMock;
  @Autowired
  @InjectMocks
  private CompanyController controller;
  private MockMvc mockMvc;
  
  @BeforeMethod
  public void setUp() {
      MockitoAnnotations.initMocks(this);
  }
  
  @DataProvider
  public static Object[][] companyJsonProvider() {
      return new Object[][]{
          {Json.createObjectBuilder()
              .add("name", "JakasFirma")
              .add("description", "jakas firma opis")
              .add("website", "www.jakasfirma.com")
              .add("logo", "jakies logo")
              .build(), status().isOk()},
          {Json.createObjectBuilder()
              .add("name", "JakasFirma")
              .build(), status().isOk()},
          {Json.createObjectBuilder()
              .add("description", "jakas firma opis")
              .add("website", "www.jakasfirma.com")
              .add("logo", "jakies logo")
              .build(), status().isBadRequest()},
          {Json.createObjectBuilder()
              .build(), status().isBadRequest()},
      };
  }
  
  @Test(dataProvider = "companyJsonProvider", enabled = false)
  public void apiTest(JsonObject companyJson, ResultMatcher expectedStatus) throws Exception {
      //given
      mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
      String content = companyJson.toString();
  
      //when
      mockMvc.perform(post("/company").contentType(MediaType.APPLICATION_JSON).content(content)).
              //then
              andExpect(expectedStatus);
  
  }
  
  @Test
  public void shouldCreate() throws Exception {
      //given
  
      //when
      controller.create(mock(Company.class));
  
      //then
      //verify(repositoryMock, times(1)).save(any(Iterable.class));
  }
  }
  </code></pre>
  
  <p>I thought about introducing a dao layer between controller and repository that could be mocked and verified bot it adds more complexity and force to encapsulate each method used by repository. Also it doesn't fix problem but partially moves it to lower level.
  Is there any method or practice that could help to deal with this kind of problem? Or maybe I should use different approach with mongo?</p>