Рефакторинг и тестирование - PullRequest
0 голосов
/ 27 октября 2011

Пример сценария, который я пытаюсь как-то юнит-тестировать:

Метод получает три параметра: Company name, Plane Number 1, Plane Number 2

public Double getDistanceBetweenPlanes(Sting company, String plane1, String plane2)
{
  -Apply some validation logic to see that plane numbers and company realy exists
  -Use complex geLocation and setelate data to get plane location

  return plane1.geoLocation() - plane2.geoLocation() ;
}

Теперь я хочу провести модульное тестирование.

У меня нет реальных номеров самолетов, у меня нет прямой связи со спутником.

Тем не менее, я бы хотел как-то смоделировать все это, чтобы протестировать этот API. Любое предложение о том, как его реорганизовать? Любой новый публичный метод, который будет создан только для тестирования?

Ответы [ 2 ]

2 голосов
/ 27 октября 2011

Обычно при рефакторинге непроверенного кода я имею в виду то, что я буду делать, работая с TDD и BDD.

Итак, сначала я бы написал простой контракт, одна строка = одно требование (из существующихкод).Затем, во время кодирования теста, я, вероятно, заметил бы вещи, которые я не хочу тестировать.В этом случае DI поможет вам удалить код, который отличается от другого класса.При работе в объектном дизайне важно сосредоточиться на поведении и взаимодействии между объектами с различными проблемами.Mockito, с псевдонимом класса BDDMockito, может помочь вам поддержать этот подход.

В вашем случае, вот пример того, что вы можете сделать.

public class PlaneLocator {
    private CompanyProvider companyProvider;
    private PlaneProvider companyProvider;
    private LocationUtil locationUtil;

    // Constructor injection or property injection

    public Double getDistanceBetweenPlanes(String companyId, String plane1Id, String plane2Id) {
        Company company = companyProvider.get(company);
        Plane plane1 = planeProvider.get(plane1Id);
        Plane plane1 = planeProvider.get(plane1Id);

        return locationUtil.distance(plane1.geoLocation(), plane2.geoLocation());
    }
}

Может выглядеть простой тест JUnit (с использованием функций из mockito 1.9.0):

@RunWith(MockitoJUnitRunner.class)
public class PlaneLocatorTest {
    @Mock CompanyProvider mockedCompanyProvider;
    @Mock PlaneProvider mockedPlaneProvider;
    @Mock LocationUtil locationUtil;
    @InjectMocks SatelitePlaneLocator testedPlaneLocator;

    @Test public void should_use_LocationUtil_to_get_distance_between_plane_location() {
        // given
        given(companyProvider.get(anyString())).willReturn(new Company());
        given(planeProvider.get(anyString()))
                .willReturn(Plane.builder().withLocation(new Location("A")))
                .willReturn(Plane.builder().withLocation(new Location("B")));

        // when
        testedPlaneLocator.getDistanceBetweenPlanes("AF", "1251", "721");

        // then
        verify(locationUtil).distance(isA(Location.class), isA(Location.class));
    }

    // other more specific test on PlaneLocator
}

И вам будут вставлены следующие зависимости: каждая имеет свой собственный модульный тест , описывающий поведение класса с учетом входных данных и соавторов:

public class DefaultCompanyProvider implements CompanyProvider {
    public Company get(String companyId) {
        companyIdValidator.validate(companyId);

        // retrieve / create the company
        return company;
    }
}
public class SatellitePlaneProvider implements PlaneProvider {
    public Plane get(Plane planeId) {
        planeIdValidator.validate(planeId);

        // retrieve / create the plane with costly satellite data (using a SatelliteService for example)
        return plane;
    }
}

Используя этот способ, вы можете реорганизовать свой код с гораздо более низкой связью.Лучшее разделение интересов позволит лучше понять основание кода, повысить удобство сопровождения и упростить эволюцию.

Я также хотел бы перенаправить вас к дальнейшему чтению в этом сообщении в блоге Приоритет преобразования в TDD от знаменитого Дядя Боб Мартин http://cleancoder.posterous.com/the-transformation-priority-premise

0 голосов
/ 27 октября 2011

Вы можете использовать макеты, такие как jmock или easy mock.

С jmock вы напишите что-то вроде этого:

@Test
public testMethod(){
 Mockery context = new Mockery();
 plane1 = context.mock(Plane.class);
 plane2 = context.mock(Plane.class);

 context.expectations(new Expectations(){{
   oneOf(plane1).geoLocation(); will(returnValue(integerNumber1));
   oneOf(plane2).geoLocation(); will(returnValue(integerNumber2));
 }});
 assertEquals(
   instanceUnderTest.method(plane1,plane2),
   integerNumber1-integerNumber2
 )
 context.assertIsSatisfied()
}  

Последний метод обеспечит вызов методов, заданных для ожиданий.,Если не возникает исключение, и тест не пройден.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...