Как мне написать Mock Object?

Моя первая работа по программированию познакомила меня с модульным тестированием и концепцией фиктивных объектов, но что-то в этом всегда было не так.

Допустим, мы пишем банковское приложение, и нам нужно смоделировать объект BankAccount:


    // boilerplate code
    public interface IBankAccount {
        void Deposit(int amount);
        void Withdrawal(int amount);
        int getBalance();
        int getAccountNumber();
    }

    public interface IBankAccountFactory {
        IBankAccount getAccount(int accountNumber);
    }

    public class ProductionBankAccountFactory implements IBankAccountFactory { 
        public IBankAccount getAccount(int accountNumber) {
            return new RealBankAccount(accountNumber);
        }
    }

    public class MockBankAccountFactory implements IBankAccountFactory {
        public IBankAccount getAccount(int accountNumber) {
            return new MockBankAccount(accountNumber);
        }
    }

    public static class BankAccountFactory {
        // ewww, singletons!
        public static IBankAccountFactory Instance;
    }

    // finally, my actual business objects
    public class MockBankAccount implements IBankAccount {
        public MockBankAccount(int accountNumber) { ... }
        // interface implementation
    }

    public class RealBankAccount implements IBankAccount {
        public RealBankAccount(int accountNumber) { ... }
        // interface implementation
    }

У каждого класса есть цель:

  • Фабричный и фабричный интерфейсы существуют для того, чтобы обернуть конструкторы для наших фиктивных и реальных объектов.
  • Статический класс BankAccountFactory позволяет нам назначить BankAccountFactory.Instance экземпляр IRealBankAccountFactory или MockBankAccountFactory в начале нашего производственного приложения или тестов соответственно.
  • Как только все настроено правильно, любой класс может получить экземпляр IBankAccount, просто вызвав:

    BankAccountFactory.Instance.getAccount(accountNum);

Это работает, но приводит к многому шаблонному коду. Мне не нужно писать 5 новых классов для каждого класса, над которым я хочу издеваться. Я убежден, что есть более простой способ, поэтому я должен спросить сообщество SO:

Есть ли лучший или предпочтительный способ написания фиктивных объектов?

[Изменить, чтобы добавить:] Я ценю ссылки на макеты и DI-фреймворки, но прямо сейчас я работаю над приложением 500 KLOC, и по крайней мере 60% кода состоит из шаблонного макета. классы в стиле выше.

Я просто хочу уменьшить размер кодовой базы, не переписывая большие куски кода для Yet-Another-Framework™, поэтому мне больше помогает увидеть фиктивные классы, написанные вручную. :)


person Juliet    schedule 15.01.2009    source источник


Ответы (3)


Лучше, если кто-то другой напишет. Вот некоторые варианты:

Moq – http://code.google.com/p/moq/

Rhino Mocks — http://ayende.com/projects/rhino-mocks.aspx

person casperOne    schedule 15.01.2009

Я предполагаю, что мой первый вопрос заключается в том, почему вам нужно использовать фабричный шаблон для обертывания конструкции ваших объектов; в частности, ваш объект Mock. Поскольку каждый модульный тест в наборе должен выполняться полностью независимо от любых других модульных тестов, кажется, что вы сможете создать экземпляр MockBankAccount непосредственно в методе setUp вашего класса модульного теста или даже в самом тесте. Если бы я был в ситуации выше, я бы написал что-то вроде этого:

public interface IBankAccount {
    void Deposit(int amount);
    void Withdrawal(int amount);
    int getBalance();
    int getAccountNumber();
}

public class MockBankAccountFactory implements IBankAccountFactory {
    public IBankAccount getAccount(int accountNumber) {
        return new MockBankAccount(accountNumber);
    }
}

public class BankAccountUnitTest extends TestCase {
    IBankAccount testBankAccount;

    public void setUp() {
        testBankAccount = new MockBankAccount(someAccountNumber);
    }

    // Unit tests here
}

Если вы используете фабрику для модульного тестирования другого класса, который использует IBankObject, вам следует изучить внедрение зависимостей для предоставления фиктивного объекта этому классу вместо того, чтобы тестируемый класс создавал фиктивный объект.

person MattK    schedule 15.01.2009

Существуют библиотеки Mock, которые упрощают процесс, позволяя указать объект и его поведение в коде модульного тестирования.

Хорошим примером является библиотека Moq (http://code.google.com/p/moq/< /а>)

person Megacan    schedule 15.01.2009