TDD - Хочет протестировать мой Уровень служб с поддельным Репозиторием, но как?

В iOS (Objective-C) я сделал это следующим образом

Вы можете добавить код ниже, чтобы программно создать папку внутри корзины Amazon 3. Это рабочий фрагмент кода. Любое предложение Добро пожаловать.

-(void)createFolder{
    AWSS3PutObjectRequest *awsS3PutObjectRequest = [AWSS3PutObjectRequest new];
    awsS3PutObjectRequest.key = [NSString stringWithFormat:@"%@/", @"FolderName"];
    awsS3PutObjectRequest.bucket = @"Bucket_Name";
    AWSS3 *awsS3 = [AWSS3 defaultS3];
    [awsS3 putObject:awsS3PutObjectRequest completionHandler:^(AWSS3PutObjectOutput * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"error Creating folder");
        }else{
            NSLog(@"Folder Creating Sucessful");
        }
    }];
}
13
задан Alex 1 June 2009 в 17:46
поделиться

7 ответов

Вам необходимо использовать внедрение зависимостей. UserRepository - это зависимость вашего класса RegistrationService. Чтобы сделать ваши классы должным образом модульными (т.е. изолированными от их зависимостей), вам необходимо «инвертировать» то, что контролирует создание ваших зависимостей. В настоящее время у вас есть прямой контроль, и вы создаете их внутри компании. Просто инвертируйте этот элемент управления и позвольте чему-то внешнему (например, контейнеру IoC, например Castle Windsor) ввести их:

public class RegistrationService: IRegistrationService
{
    public RegistrationService(IRepository<User> userRepo)
    {
        m_userRepo = userRepo;
    }

    private IRepository<User> m_userRepo;

    public void Register(User user)
    {
        // add user, etc with m_userRepo
    }
}

Кажется, я забыл добавить. Как только вы позволите внедрить свои зависимости, вы откроете возможность их издевательства. Поскольку ваша RegistrationService теперь принимает свой зависимый пользовательский репозиторий в качестве входных данных для своего конструктора, вы можете создать фиктивный репозиторий и передать его вместо реального репозитория.

16
ответ дан 1 December 2019 в 20:43
поделиться

Вы можете использовать контейнер IOC, а затем зарегистрировать другой репозиторий.

0
ответ дан 1 December 2019 в 20:43
поделиться

Просто чтобы добавить немного ясности (или, возможно, нет) к тому, что все сказали, способ, которым в основном работает IOC, - это вы говорите ему заменить X на Y. Итак, что вы сделаете, это согласитесь IRepository (как утверждали другие) в качестве параметра, а затем в IOC вы бы сказали ему заменить IRepository на MockedRepository (например) для этого конкретного класса.

Если вы используете IoC, который позволяет инициализировать web.config, он делает переход от разработчика к продукту очень плавным. Вы просто изменяете соответствующие параметры в файле конфигурации, и вы уже в пути - без необходимости касаться кода. Позже, если вы решите, что хотите перейти к другому источнику данных - просто отключите его, и вы уже в пути.

IoC - это кое-что забавное.

Кстати, вы можете сделать это и без инъекции IOC, если все, что вам нужно, это Unit Test. Вы можете сделать это, перегрузив конструктор, чтобы он принял IRepository, и просто передав таким образом свое фиктивное репо.

1
ответ дан 1 December 2019 в 20:43
поделиться

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

0
ответ дан 1 December 2019 в 20:43
поделиться

Внедрение зависимостей может очень пригодиться для таких вещей:

public class RegistrationService: IRegistrationService
{
    public void Register(User user)
    {
        this(user, new UserRepository());
    }

    public void Register(User user, IRepository<User> userRepository)
    {
        // add user, etc
    }

}

Таким образом, вы получаете возможность использовать UserRepository по умолчанию и передавать пользовательские (Mock или Stub для тестирования ) IRepository для всего, что вам нужно. Вы также можете изменить область действия метода второго регистра, если вы не хотите открывать его для всего.

Еще лучшей альтернативой было бы использование контейнера IoC, который купит вам синтаксис, который еще более развязан чем в приведенном выше примере. Вы можете получить что-то вроде этого:

public class RegistrationService: IRegistrationService
{
    public void Register(User user)
    {
        this(user, IoC.Resolve<IRepository<User>>());
    }

    public void Register(User user, IRepository<User> userRepository)
    {
        // add user, etc
    }

}

Существует много контейнеров IoC, как указано в ответах других людей, или вы можете использовать свой собственный .

9
ответ дан 1 December 2019 в 20:43
поделиться

Вам следует использовать инверсию управления или внедрение зависимостей.

Ваши классы не должны быть привязаны к реализации другого класса, особенно между такими слоями, как этот, скорее, это должно быть возьмите интерфейс, представляющий пользовательский репозиторий либо как конструктор, либо как свойство. Затем, когда он запускается, вы предоставляете конкретную реализацию, и она ее использует. Затем вы можете создавать подделки, которые реализуют интерфейс репозитория и предоставлять их во время тестирования.

Существует очень много контейнеров IOC, Unity, Ninject, Castle Windsor и StructureMap, чтобы назвать некоторые.


Я просто хотел внести ясность. , я не знаю, во время ваших модульных тестов вы действительно хотели бы использовать контейнер IOC. Интеграционные тесты, конечно, но для юнит-тестов просто обновите объект, который вы тестируете, и предоставьте свою фальшивку во время этого процесса. Контейнеры IOC, по крайней мере, IMO, помогают на уровне тестирования приложений или интеграции и упрощают настройку.

Ваши модульные тесты, вероятно, должны оставаться «чистыми» и работать только с объектами, которые вы пытаетесь тестировать. По крайней мере, у меня это работает.

2
ответ дан 1 December 2019 в 20:43
поделиться

Я сейчас над чем-то работаю, ну, почти дословно. Я использую MOQ для создания модели прокси-экземпляра моего IUserDataRepository.

С точки зрения тестирования:

//arrange
var mockrepository = new Mock<IUserDataRepository>();
// InsertUser method takes a MembershipUser and a string Role
mockrepository.Setup( repos => repos.InsertUser( It.IsAny<MembershipUser>(), It.IsAny<string>() ) ).AtMostOnce();

//act
var service = new UserService( mockrepository.Object );
var createResult = service.CreateUser( new MembershipUser(), "WebUser" );

//assert
Assert.AreEqual( MembershipCreateUserResult.Success, createResult );
mockrepository.VerifyAll();

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

] Затем, как уже упоминалось другими, IoC будет обрабатывать требуемые зависимости. В этом случае создается реальный репозиторий для класса UserService.

1
ответ дан 1 December 2019 в 20:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: