testing

Mocking Fog with CarrierWave and Minitest

I kept getting the  error

Expected(200) <=> Actual(404 Not Found)

while trying to use Fog.mock! in unit tests.  I followed the guidelines in Fog and Carrierwave, but no luck.  Here’s the trick:  Fog uses credentials to segregate mock data, so be sure the controllers and tests are using the same credentials.

Final setup:

carrierwave.rb

CarrierWave.configure do |config|
  s3_config = YAML::load(File.read(Rails.root.join('config','s3.yml')))[Rails.env]

  config.fog_credentials = {
    :provider => 'AWS',
    :aws_access_key_id => s3_config['access_key_id'],
    :aws_secret_access_key => s3_config['secret_access_key'],
  }
  config.fog_directory = s3_config['bucket_name']
  config.fog_public = false
  config.fog_authenticated_url_expiration = 1800 # (in seconds) => 30 minutes

  if Rails.env.test?
    config.enable_processing = false
  end
end

s3.yml

test:
  bucket_name: testbucket
  access_key_id: secretkeyid
  secret_access_key: secretaccesskey

test_helper.rb

Fog.mock!
service = Fog::Storage.new({
  :provider                 => 'AWS',
  :aws_access_key_id        => 'secretkeyid',
  :aws_secret_access_key    => 'secretaccesskey'
})
service.directories.create(:key => 'testbucket')

Helpful links:

Version Info:

  • Rails 4.2.6, Ruby 2.2.4
  • carrierwave 0.11.0
  • fog 1.38.0
  • fog-aws 0.9.2

 

Advertisements

Spring 3 @Autowired Unit Tests with Mockito

I’ve been wanting to enhance the unit tests I have in my application for awhile. I’m using Spring 3 testing facilities, but most of my tests are “integration” tests. I finally carved out a bit of time to enable better unit tests in my application. This is an example of a unit test of a simple service class using Spring 3 annotations. I am using Mockito to mock the dependencies.

First my service class. Like I said, simple. Just two methods and straightforward logic.

package my.app.service;

import java.util.List;

import my.app.dao.SupervisorDAO;
import my.app.model.Supervisor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SupervisorService {

	@Autowired private SupervisorDAO supervisorDao;

	@Transactional(readOnly=true)
	public List getSupervisors() {
		return supervisorDao.getSupervisors();
	}

	/**
	 * Determine if the supervisor is responsible for any users for the
	 * specified department
	 * @param dbId The dbId of the supervisor
	 * @param department The department to look for
	 * @return true if there are users assigned to the superivsor for the department
	 */
	public boolean isSupervisorResponsibleForUser(int dbId, String department) {
		if (dbId == 0) {
			throw new IllegalArgumentException("A dbId is required");
		}
		if (department == null) {
			throw new IllegalArgumentException("department is required");
		}
		boolean hasUsers = false;
		int numAssignedUsers = supervisorDao.getUserCountForSupervisor(dbId, department);
		if (numAssignedUsers > 0) {
			hasUsers = true;
		}
		return hasUsers;
	}
}

The unit test. I need to mock the dao object to create a repeatable unit test of the service class. Here’s the code:

package my.app.service;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import my.app.dao.SupervisorDAO;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class SupervisorServiceUnitTest {

	@Mock private SupervisorDAO mockSupervisorDao;
	@InjectMocks private SupervisorService supervisorService;

	@Before
	public void init() {
		when(mockSupervisorDao.getUserCountForSupervisor(1, "Department1"))
			.thenReturn(2);
		when(mockSupervisorDao.getUserCountForSupervisor(1, "Department2"))
			.thenReturn(0);
	}

	@Test
	public void testIsSupervisorResponsibleForUserTrue() {
		boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department1");
		assertTrue(isSupervisor);
	}

	@Test
	public void testIsSupervisorResponsibleForUserFalse() {
		boolean isSupervisor = supervisorService.isSupervisorResponsibleForUser(1, "Department2");
		assertFalse(isSupervisor);
	}

	@Test(expected=IllegalArgumentException.class)
	public void testIsSupervisorResponsibleRequiredDbId() {
		supervisorService.isSupervisorResponsibleForUser(0, "Department3");
	}

	@Test(expected=IllegalArgumentException.class)
	public void testIsSupervisorResponsibleRequiredDivision() {
		supervisorService.isSupervisorResponsibleForUser(1, null);
	}
}

The key things that I learned along the way:

  • Use @RunWith(MockitoJUnitRunner.class) to run this test
  • Use the @Mock annotation for the classes that need to be mocked within the class you are testing. Use the @InjectMocks annotation on the class you are testing. The @Mock classes are injected into the @InjectMocks class. I guess this should have been obvious, but it wasn’t to me.

It’s a simple class and a simple unit test, but it’s a start. It gets me over the hump of having the correct jars and knowing how to get a test up and running. I am new to the behavior driven style of Mockito, but this works well for me in this unit test. I think it is clean and easy to read.

Some links that were helpful to me (disclaimer, some of these are for older versions of Mockito)

Version Info:

  • Spring 3.0.5
  • Mockito 1.9.0