표준 Ruby Test::Unit
프레임 워크를 사용하여 Ruby에서 보호 및 개인 메소드를 단위 테스트하는 가장 좋은 방법은 무엇입니까 ?
누군가 공개적으로 분석 할 때는 “공용 메소드 만 단위 테스트해야합니다. 단위 테스트가 필요한 경우 보호 된 방법이나 비공개 방법이 아니어야합니다”라고 확신하지만 실제로는 그 논쟁에 관심이 없습니다. 나는 여러 가지 방법을 가지고 있습니다 보호 또는 좋은 유효한 이유로 개인을, 그러므로 내가 테스트하는 방법이 필요합니다, 이러한 개인 / 보호 방법은 적당히 복잡하고, 클래스의 public 메소드가 제대로 작동이 보호 / 개인 방법에 의존 보호 / 비공개 방법
한가지 더 … 나는 일반적으로 주어진 클래스에 대한 모든 메소드를 하나의 파일에 넣고, 유닛은 그 클래스에 대한 다른 파일을 테스트합니다. 이상적으로는 주 소스 파일을 가능한 한 간단하고 간단하게 유지하기 위해이 “보호 및 개인 메소드의 단위 테스트”기능을 주 소스 파일이 아닌 단위 테스트 파일에 구현하는 것이 가장 좋습니다.
답변
send 메소드를 사용하여 캡슐화를 우회 할 수 있습니다.
myobject.send(:method_name, args)
이것은 루비의 ‘기능’입니다. 🙂
루비 1.9 개발 과정에서 send
프라이버시 를 존중하고 send!
무시 하는 것을 고려한 내부 논쟁이 있었지만, 결국 루비 1.9에서는 아무것도 바뀌지 않았습니다. 아래 내용을 논의 send!
하고 깨뜨리는 의견은 무시하십시오 .
답변
RSpec을 사용하는 쉬운 방법은 다음과 같습니다.
before(:each) do
MyClass.send(:public, *MyClass.protected_instance_methods)
end
답변
테스트 파일에서 클래스를 다시 열고 메소드를 공개로 다시 정의하십시오. 메소드 자체의 내장을 재정의 할 필요는 없으며 심볼을 public
호출에 전달하면됩니다 .
원래 클래스가 다음과 같이 정의 된 경우 :
class MyClass
private
def foo
true
end
end
테스트 파일에서 다음과 같이하십시오.
class MyClass
public :foo
end
public
더 많은 개인용 메소드를 노출하려는 경우 여러 기호를 전달할 수 있습니다 .
public :foo, :bar
답변
instance_eval()
도움이 될 수 있습니다.
--------------------------------------------------- Object#instance_eval
obj.instance_eval(string [, filename [, lineno]] ) => obj
obj.instance_eval {| | block } => obj
------------------------------------------------------------------------
Evaluates a string containing Ruby source code, or the given
block, within the context of the receiver (obj). In order to set
the context, the variable self is set to obj while the code is
executing, giving the code access to obj's instance variables. In
the version of instance_eval that takes a String, the optional
second and third parameters supply a filename and starting line
number that are used when reporting compilation errors.
class Klass
def initialize
@secret = 99
end
end
k = Klass.new
k.instance_eval { @secret } #=> 99
이를 사용하여 개인용 메소드 및 인스턴스 변수에 직접 액세스 할 수 있습니다.
또한 send()
James Baker가 제안한 것처럼 비공개 및 보호 된 메소드에 액세스 할 수있는
또는 테스트 객체의 메타 클래스를 수정하여 프라이빗 / 보호 된 메소드를 해당 객체에 대해서만 공개 할 수 있습니다.
test_obj.a_private_method(...) #=> raises NoMethodError
test_obj.a_protected_method(...) #=> raises NoMethodError
class << test_obj
public :a_private_method, :a_protected_method
end
test_obj.a_private_method(...) # executes
test_obj.a_protected_method(...) # executes
other_test_obj = test.obj.class.new
other_test_obj.a_private_method(...) #=> raises NoMethodError
other_test_obj.a_protected_method(...) #=> raises NoMethodError
이를 통해 해당 클래스의 다른 객체에 영향을주지 않고 이러한 메소드를 호출 할 수 있습니다. 테스트 디렉토리 내에서 클래스를 다시 열고 테스트 코드 내의 모든 인스턴스에 대해 공개 할 수 있지만 공개 인터페이스 테스트에 영향을 줄 수 있습니다.
답변
과거에 내가 한 일 중 하나는 다음과 같습니다.
class foo
def public_method
private_method
end
private unless 'test' == Rails.env
def private_method
'private'
end
end
답변
누군가 공개적으로 분석 할 때는 “공용 메소드 만 단위 테스트해야합니다. 단위 테스트가 필요한 경우 보호 된 방법이나 비공개 방법이 아니어야합니다”라고 확신하지만 실제로는 그 논쟁에 관심이 없습니다.
또한 메소드를 공용 인 새 객체로 리팩토링하고 원래 클래스에서 비공개로 위임 할 수도 있습니다. 이를 통해 스펙에 매직 메타 루비가없는 메소드를 테스트하면서 비공개로 유지할 수 있습니다.
타당한 이유 때문에 보호되거나 비공개 인 몇 가지 방법이 있습니다.
그 유효한 이유는 무엇입니까? 다른 OOP 언어는 개인 메소드 없이도 얻을 수 있습니다 (개인 메소드는 규칙으로 만 존재하는 스몰 토크가 떠 오릅니다).
답변
@WillSargent의 응답과 마찬가지로, 여기에 FactoryGirl을 사용하여 describe
작성 / 업데이트하는 무거운 프로세스를 거치지 않고도 일부 보호 유효성 검사기를 테스트하는 특별한 경우를 위해 블록 에서 사용한 내용 이 있습니다 (private_instance_methods
유사하게 ).
describe "protected custom `validates` methods" do
# Test these methods directly to avoid needing FactoryGirl.create
# to trigger before_create, etc.
before(:all) do
@protected_methods = MyClass.protected_instance_methods
MyClass.send(:public, *@protected_methods)
end
after(:all) do
MyClass.send(:protected, *@protected_methods)
@protected_methods = nil
end
# ...do some tests...
end