-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix create balance when incomplete data #315
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
defmodule Teiserver.Battle.BalanceLibInternalTest do | ||
@moduledoc """ | ||
Can run all balance tests via | ||
mix test --only balance_test | ||
""" | ||
use Teiserver.DataCase, async: true | ||
@moduletag :balance_test | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not convinced by this tag. Test tags should be used for logical grouping only. Like I think that tag could make sense for all balance related tests. But in this case, let's make another PR that tags all the relevant tests at once. And the tag should only be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other balance tests are tagged already though. So it's hitting multiple files. |
||
alias Teiserver.Battle.BalanceLib | ||
|
||
test "Able to standardise groups with incomplete data" do | ||
[user1, user2, user3, user4, user5] = create_test_users() | ||
|
||
groups = [ | ||
%{user1.id => 19, user2.id => 20}, | ||
%{user3.id => 18}, | ||
%{user4.id => 15}, | ||
%{user5.id => 11} | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not a fan at all of the use of mocks. It forces you to have a deep knowledge of the internals of the stuff you're testing. You recognise that with the comment a bit bellow:
It's also a departure from the other tests elsewhere. For these reason, I'd rather have something that creates the mock data in the DB, and then exercise the code under test. Using [user1, user2, user3, user4, user5] =
Enum.map(1..5, fn k ->
Teiserver.TeiserverTestLib.new_user("User_#{k}")
end)
groups = [
%{user1.id => 19, user2.id => 20},
%{user3.id => 18},
%{user4.id => 15},
%{user5.id => 11}
]
fixed_groups = BalanceLib.standardise_groups(groups)
assert fixed_groups == [
%{
user1.id => %{name: "User_1", rank: 0, rating: 19},
user2.id => %{name: "User_2", rank: 0, rating: 20}
},
%{user3.id => %{name: "User_3", rank: 0, rating: 18}},
%{user4.id => %{name: "User_4", rank: 0, rating: 15}},
%{user5.id => %{name: "User_5", rank: 0, rating: 11}}
] and similar for the other test. You could even consider pulling the creation of users in a setup function for the module. Let me know if you have any question over this code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just tested this and any db changes are persisted between tests which means I cannot call TeiserverTestLib.new_user at beginning of each test. That function will create a user with a random name if it finds the user already exists. It's really weird. If I call the test multiple times it will eventually fail. |
||
|
||
fixed_groups = BalanceLib.standardise_groups(groups) | ||
|
||
assert fixed_groups == [ | ||
%{ | ||
user1.id => %{name: "User_1", rank: 0, rating: 19}, | ||
user2.id => %{name: "User_2", rank: 0, rating: 20} | ||
}, | ||
%{user3.id => %{name: "User_3", rank: 0, rating: 18}}, | ||
%{user4.id => %{name: "User_4", rank: 0, rating: 15}}, | ||
%{user5.id => %{name: "User_5", rank: 0, rating: 11}} | ||
] | ||
|
||
# loser_picks algo will hit the databases so let's just test with split_one_chevs | ||
result = BalanceLib.create_balance(fixed_groups, 2, algorithm: "split_one_chevs") | ||
assert result != nil | ||
end | ||
|
||
test "Handle groups with incomplete data in create_balance loser_pics" do | ||
[user1, user2, user3, user4, user5] = create_test_users() | ||
|
||
groups = [ | ||
%{user1.id => 19, user2.id => 20}, | ||
%{user3.id => 18}, | ||
%{user4.id => 15}, | ||
%{user5.id => 11} | ||
] | ||
|
||
# loser_picks algo will hit the databases so let's just test with split_one_chevs | ||
result = BalanceLib.create_balance(groups, 2, algorithm: "loser_picks") | ||
assert result != nil | ||
end | ||
|
||
test "Handle groups with incomplete data in create_balance split_one_chevs" do | ||
[user1, user2, user3, user4, user5] = create_test_users() | ||
|
||
groups = [ | ||
%{user1.id => 19, user2.id => 20}, | ||
%{user3.id => 18}, | ||
%{user4.id => 15}, | ||
%{user5.id => 11} | ||
] | ||
|
||
# loser_picks algo will hit the databases so let's just test with split_one_chevs | ||
result = BalanceLib.create_balance(groups, 2, algorithm: "split_one_chevs") | ||
assert result != nil | ||
end | ||
|
||
defp create_test_users do | ||
Enum.map(1..5, fn k -> | ||
Teiserver.TeiserverTestLib.new_user("User_#{k}") | ||
end) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this bit correctly, when the value in the map is not a user struct, you want to fetch the corresponding user and replace the id with that user right?
In that case there's a much simpler way:
Enum.map
or, if you prefer using guards, you can also do the following
The advantage of
Enum.map
is that the intent is clearer, you are applying some sort of transformation on every element. In the case of a map it's a tuple of{key, value}
.When using
map_reduce
, it's a lot more complicated to figure out what's going on. The fact that you had to discard one of the return value is a code smell as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a feeling there was a better way to do it. Before you reviewed this, I had already posted a question on Elixir forums: https://elixirforum.com/t/iterate-through-map-of-dynamic-keys-and-update-their-values/64061/3
I'm liking the idea of Map.new