Модульное тестирование: TypeMocking одиночного - PullRequest
1 голос
/ 07 апреля 2009

Я использую TypeMock Isolater для макетирования некоторых объектов для некоторых модульных тестов - пытаюсь использовать API AAA (так вызывает Isolate).

У меня есть простой одноэлементный класс, где вы вызываете статический метод GetInstance (), который затем возвращает экземпляр класса. Я подумала, что это будет просто издеваться, но я сталкиваюсь с очень неприятной проблемой! Кажется, я не могу заставить GetInstance () правильно возвращать мой смоделированный объект с моими ожидаемыми вызовами.

Я пробовал:

  • использование проектов MST (с использованием классов Accessor) для назначения макетируемого объекта непосредственно переменной экземпляра (фальсификация объекта с использованием Memers.MustSpecifyReturnValues ​​и Isolate.WhenCalled с использованием WithExactArguments для установки ожиданий), но по какой-то причине mocked объект всегда возвращает ноль (и без исключений).
  • Mocking Singleton.GetInstance () для возврата смоделированного объекта. Это возвращает фиктивный объект, который нуждается в установке WhenCalled, но теперь вызываемые мной вызовы Isolate.WhenCalled, похоже, ничего не делают с фальшивым объектом - поэтому все вызовы выдают неожиданное исключение вызова.
  • Я также пытался смоделировать фактический вызов метода (например, Singleton.GetInstance (). Test ()), который будет работать для вызова этого метода, но все другие вызовы других методов в синглтоне возвращают нуль, а не бросить исключение так, как я хочу (потому что это, кажется, автоматически макетирует все объекты без Members.MustSpecifyReturnValues).

Все, что я хочу, - это смоделировать синглтон, и любые вызовы, о которых я прямо не говорю, должны ожидать исключения. Я думал, что это будет просто, но, видимо, нет! Sad

Кто-нибудь знает, что я делаю не так?

Спасибо Джеймс

Ответы [ 4 ]

3 голосов
/ 07 апреля 2009

Я думаю, что простым решением будет создание поддельного экземпляра синглтон-класса и использование SwapNextInstace до вызова фактического конструктора класса:

[TestMethod]
public void SetBhaciorOnSingleton()
{
   var fake = Isolate.Fake.Instance<SingletonClass>();

   Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);
   // Set additional behavior on singleton class

   Isolate.Swap.NextInstance<SingletonClass>().With(fake);

   // This is where the class constructor is being called
   var result = SingletonClass.GetInstace().SomeFunction();
   Assert.AreEqual(10, result );
}

Это решение должно работать с большинством сценариев, если класс singleton не создан перед тестом. Если вам нужно установить поведение после создания класса, просто используйте WhenCalled:

[TestMethod]
public void SetBhaciorOnSingleton()
{
    var fake = Isolate.Fake.Instance<SingletonClass>();

    Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);

    Isolate.WhenCalled(() => SingletonClass.GetInstace()).WillReturn(fake);

    var result = SingletonClass.GetInstace().SomeFunction();
    Assert.AreEqual(10, result );
}
2 голосов
/ 16 февраля 2016

Отказ от ответственности Я работаю в Typemock.

Вам не нужно издеваться над Singleton.GetInstance <> (). Используя Isolate.Fake.AllInstances <> () вместо Isolate.Fake.Instance <> (), вы можете издеваться над синглтоном. Затем, установив поведение на поддельное синглтонное поведение, применяется ко всем экземплярам.

Взгляните на пример:

public class Singleton
    {
        private Singleton() { }
        static readonly Singleton instance = new Singleton();

        public static Singleton Instance { get {  return instance; } }

        public int ReturnZero()
        {
            return 0;
        }
    }

    [TestMethod]
    public void FakeSingleton()
    {
        // Here we are setting the same behavior on all instances.
        // The behavior we set on fake will apply to past instance as well
        var fakeSingleton = Isolate.Fake.AllInstances<Singleton>();
        Isolate.WhenCalled(() => fakeSingleton.ReturnZero()).WillReturn(10);

        // Assert that the behavior works.
        Assert.AreEqual(10, Singleton.Instance.ReturnZero());
    }
0 голосов
/ 07 апреля 2009

Спасибо.

Я раньше не пробовал NextInstance, потому что он не работает на интерфейсах, которые я не хотел менять.

Но я попробовал это, и оно работает - хотя я предполагал, что порядок установки WhenCalled (s) на самом деле не имеет значения, но определенно имеет значение. Если я сделаю WhenCalled после Swap, например, это не сработает. Это должно идти до обмена. (Для меня не имеет смысла быть честным - это должен быть один и тот же объект).

Однако последний пример (один из способов, который я пробовал) не работает для меня. Я подделываю, задаю для фальшивого ожидания, а затем для Синглтона устанавливаю ожидание возврата фальшивого экземпляра - но теперь он возвращает конкретный экземпляр!

Может ли это быть связано с тем, как называются конструкторы? Я помню, что видел что-то об этом ...

В качестве альтернативы я мог бы использовать своп, но я хотел иметь возможность настроить все эти вещи в TestSetup и внести незначительные изменения в ожидания в реальном тесте, но это не представляется возможным.

0 голосов
/ 07 апреля 2009

Лучшее решение - не использовать синглтоны (или любые другие статические изменяемые данные). Просто создайте один экземпляр и используйте внедрение зависимостей, чтобы передать его всем нуждающимся объектам.

...