我有两个哈希h1
和h2
,我想在RSpec中进行比较。
我想检查一些转换后h1
的元素是否与h2
相同,我们称之为f
。也就是说,我想验证k
中的每个键h1
,h1[k] == f(h2[k])
。
例如,如果h2
中的所有值都是h1
中相应值的两倍,那么我想检查h1中每个键k
的值,{{ 1}}。
在RSpec中执行此操作的正确方法是什么?目前我这样做:
h2[k] == h1[k] * 2
但这似乎很笨拙。
答案 0 :(得分:5)
听起来你正在测试的是转型。我会考虑写这样的东西:
expected: {:k1=>2, :k2=>4}
got: {:k1=>1, :k2=>4}
(compared using ==)
Diff:
@@ -1,3 +1,3 @@
-:k1 => 2,
+:k1 => 1,
:k2 => 4,
对我来说,描述清楚地说明了我们的期望。然后我可以很容易地从测试中看到输入是什么和预期的输出。此外,这会利用哈希匹配器,它将在失败时为两个哈希提供一个很好的差异:
public class ButtonControler {
Activity mActivity;
public ButtonControler(Activity activity) {
mActivity = activity;
}
public void buttonPressed() {
//add the buttons contorls
//if the top button is pushed get the promotion page
final ImageButton promo = (ImageButton) mActivity.findViewById(R.id.apivita);
promo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent getPromos = new Intent(v.getContext(), PromotionMain.class);
mActivity.startActivity(getPromos);
}
});
//if the button 1 is pushed get the defulat webview page
final ImageButton button1 = (ImageButton) mActivity.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Button1: ", "Pressed");
Intent button1Pressed = new Intent(v.getContext(), MyWebViewMain.class);
mActivity.startActivity(button1Pressed);
}
});
//if the cart is pushed get the cart webview page
final ImageButton cart = (ImageButton) mActivity.findViewById(R.id.button2);
cart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Cart: ", "Pressed");
Intent myCart = new Intent(v.getContext(), Cart.class);
mActivity.startActivity(myCart);
}
});
//if the button 3 is pushed get the defulat webview page
final ImageButton button3 = (ImageButton) mActivity.findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Button3: ", "Pressed");
Intent buttonPressed = new Intent(v.getContext(), MyWebViewMain.class);
mActivity.startActivity(buttonPressed);
}
});
//if the button 4 is pushed get the defulat webview page
final ImageButton button4 = (ImageButton) mActivity.findViewById(R.id.button4);
button4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Button4: ", "Pressed");
Intent buttonPressed = new Intent(v.getContext(), MyWebViewMain.class);
mActivity.startActivity(buttonPressed);
}
});
//if the Store list is pushed get the defulat webview page
final ImageButton storeList = (ImageButton) mActivity.findViewById(R.id.button5);
storeList.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("StoreList: ", "Pressed");
Intent myStoreList = new Intent(v.getContext(), StoreList.class);
mActivity.startActivity(myStoreList);
}
});
//if the Store list is pushed get the notification
final Button notification = (Button) mActivity.findViewById(R.id.gcmlogo);
notification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Notificatiion: ", "Pressed");
Intent myNotification = new Intent(v.getContext(), GCMMainActivity.class);
mActivity.startActivity(myNotification);
}
});
//if the Store list is pushed get the notification
final Button myPage = (Button) mActivity.findViewById(R.id.mypage);
myPage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("MyPage: ", "Pressed");
//read the stored values
String storedUser = CustomerPerferences.readString(mActivity.getApplicationContext(), CustomerPerferences.USER_NAME, "");
String storedPass = CustomerPerferences.readString(mActivity.getApplicationContext(), CustomerPerferences.PASSWORD, "");
//see if use has entered a username and password
if (storedUser.equals("USER_NAME")) {
Log.d("Loging in", "Go!");
Intent goToLogin = new Intent(v.getContext(), LoginPage.class);
mActivity.startActivity(goToLogin);
} else {
Intent goToLogin = new Intent(v.getContext(), CustomerPage.class);
goToLogin.putExtra("user_name", storedUser);
mActivity.startActivity(goToLogin);
}
}
});
}
}
虽然我会质疑键值关系的含义。这些只是您试图通过的测试用例吗?如果是这样,我只会让每个人都进行独特的测试。如果还有更多内容,那么我可能会质疑为什么变换方法没有提供哈希开始。
答案 1 :(得分:1)
h1.each do |k, v|
expect(v).to eq(f(h2[k]))
end
至于我,它似乎更具可读性。
答案 2 :(得分:1)
怎么样:
h2 = f(h1)
expect(h2.keys).to eq(h1.keys) # I assume you want this, too
h1.keys.each do |k|
expect(h2[k]).to eq(h1[k] * 2)
end
多一点啰嗦,但也许更具可读性?
答案 3 :(得分:1)
我们在 RSpecs 中使用 hashdiff 来处理这个问题。
我们开发了一个自定义匹配器:
RSpec::Matchers.define :match_hash do |expected|
match do |actual|
Hashdiff.best_diff(expected, actual).blank?
end
failure_message do |actual|
"expected that #{actual} would match #{expected}, but it has these differences: #{Hashdiff.best_diff(expected, actual)}"
end
end
我们像这样使用它:expect(actual_hash).to match_hash(expected_hash)
答案 4 :(得分:0)
为了完全平等:
expect(h1).to eq h2.map { |k, v| [k, f(v)] }.to_h
答案 5 :(得分:0)
如果有人要为嵌套大哈希寻找更好的差异,我想出了这一点:
import sympy as sp
sp.var("a, b, c, d, z")
myeq = sp.Eq(c * sp.sin(a * (b / 2 - z)) + d * sp.cos(a * (b / 2 - z)), 0)
sol = sp.solve(myeq, z)
print(sol)
Output: [(a*b - 4*atan((c - sqrt(c**2 + d**2))/d))/(2*a), (a*b - 4*atan((c + sqrt(c**2 + d**2))/d))/(2*a)]
原始要点:https://gist.github.com/fabriciofreitag/b7458725ffef08eaf5ea541c95385a92