Должны ли данные в тесте BDD работать или только проверять состояние? - PullRequest
1 голос
/ 02 марта 2011

Должен ли данный оператор в сценарии BDD работать или только проверять состояние?

Например, рассмотрим следующий пример: «Учитывая, что я вошел в систему» ​​

Должен ли журнал определения шагапользователь или он должен только подтвердить, что я вошел в систему?

Если он должен только проверить, что я вошел в систему, то как мне на самом деле войти?

Ответы [ 2 ]

1 голос
/ 03 марта 2011

В синтаксисе стиля RSpec, о котором я думаю, когда вы говорите «тест BDD», «данный» будет частью блока «описать» или «контекст», который отвечает за получение тестируемых компонентов в правильное состояние и не несет ответственности за какие-либо утверждения или проверку поведения компонента в этом состоянии.

«данное» будет выполнять настройку вашего компонента, а затем «оно» или «следует», которое проверяет некоторое поведение.

describe ClassUnderTest do
  describe "some feature" do
    context "given that I am logged in" do
      before do
        sign_in Factory :user
      end
      it "has some behavior" do
        #make some assertion about the ClassUnderTest's behavior
      end
    end
  end
end

Я думаю, что Джаред описал хорошую структуру для структурирования тестов BDD, если Ruby и RSpec полезны для вас: http://blog.carbonfive.com/2010/10/21/rspec-best-practices/

1 голос
/ 02 марта 2011

Ответ зависит от того, что вы пытаетесь проверить.Пример звучит как что-то из огурца, но вы использовали термин BDD.Я связываю BDD с модульным тестированием снизу вверх.Если это так, предположим, что у вас есть некоторый класс аутентификации и пользовательский класс.

Класс пользователя:

public class User : IUser
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
}

public interface IUser
{
    int ID { get; }
    string Name { get; }
    string Password { get; }
}

Класс аутентификатора:

    public class Authenticator : IAuthenticator
    {
        public Authenticator()
        {
            //Initialize and acquire some authentication mechanism (db, service, file, etc..)
        }

        public bool IsLoggedIn(IUser user)
        {
            return true;
        }
        public bool LoginUser(IUser user)
        {
            //Do real login.
            return true;
        }

        public bool LogoutUser(IUser user)
        {
            //Do real logout.
            return true;
        }
    }

    public interface IAuthenticator
    {
        bool LoginUser(IUser user);
        bool LogoutUser(IUser user);
    }

Класс UserActions для вызова аутентификатора, управления разрешениями и т. Д .:

public class UserActions
{
    private readonly IAuthenticator _authenticator;
    private readonly IUser _user;
    //private Permissions Permissions;

    public UserActions(IUser user)
        : this(new Authenticator(), user)
    { }

    public UserActions(IAuthenticator authenticator, IUser user)
    {
        _authenticator = authenticator;
        _user = user;
    }

    public bool Login()
    {
        var result = _authenticator.LoginUser(_user);
        return result;
    }

    public void Logout()
    {
        _authenticator.LogoutUser(_user);
    }
}

С этими классами я бы попытался проверить поведение (используя NUnit и MOQ) класса UserActions в отношении входа в систему ивыход из системыВ этом примере никакая работа не выполняется, но для примера представьте себе более полную реализацию:

[TestFixture]
public class Tester
{
    [Test]
    public void CanLoginGoodUser()
    {
        IUser user = new User { ID = 1, Name = "Test1", Password = "good" };
        var authenticator = new Mock<IAuthenticator>();
        authenticator.Setup(a => a.LoginUser(user)).Returns(true);

        var action = new UserActions(authenticator.Object, user);
        action.Login();
        authenticator.Verify(a => a.LoginUser(It.Is<IUser>(u => u == user)), Times.AtLeastOnce());
    }

    [Test]
    public void WontLoginBadUser()
    {
        IUser user = new User { ID = 1, Name = "Test1", Password = "bad" };
        var authenticator = new Mock<IAuthenticator>();
        authenticator.Setup(a => a.LoginUser(user)).Returns(false);

        var action = new UserActions(authenticator.Object, user);
        action.Login();
        authenticator.Verify(a => a.LoginUser(It.Is<IUser>(u => u == user)), Times.AtLeastOnce());
    }
}

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

Я уверен, что другие люди не согласятся с этим подходом, но это то, чем я сейчас занимаюсь.Он хорошо работает для меня в том смысле, что он позволяет проводить тестирование по принципу «снизу вверх», охват кода и проблемы разделения при разработке моего класса.

...