Skip to content
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

Add check in unfeasible analyzer: unit tests #1716

Conversation

sylvlecl
Copy link
Member

Description
Adding some unit tests on top of #1689 and of existing code.

Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
…analyzer' into feature/add_check_in_unfeasible_analyzer_unit_tests
Signed-off-by: Sylvain Leclerc <[email protected]>
Signed-off-by: Sylvain Leclerc <[email protected]>
/*!
* Analysis mock, used to assess which step has been run by the analyzer
*/
class AnalysisMock : public UnfeasibilityAnalysis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with another C++ unit test library (see GoogleTest, catch 2, CppUTest, ...), we wouldn't need this mock class, and we would need variables like hasRun1, hasPrinted1, ....
We should consider adopting one of these unit tests framework

analysis.push_back(std::make_unique<AnalysisMock>(true, hasRun2, hasPrinted2));
std::unique_ptr<MPSolver> problem(MPSolver::CreateSolver("GLOP"));

UnfeasiblePbAnalyzer analyzer(std::move(analysis));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the use of std::move here, as it's used as well in the constructor initialization list ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, necessary for the compiler, because the vector is move-only (because its content is move-only).
without std::move I guess the compiler tries to perform a copy.


BOOST_AUTO_TEST_SUITE(unfeasible_problem_analyzer)

BOOST_AUTO_TEST_CASE(test_problem_analyzer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name is starts with test_ : we know the context is unit test, so this prefix is useless, don't you think ?
Here we could call the test : probe every step of unfeasible analysis ? (may be there's a better name)
Please see next comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I changed the namings according to your input, thank you!
In particular, I indeed removed the test_ prefix, and tried to give a small explanation of the expected behavior ("should" do this).

};


BOOST_AUTO_TEST_SUITE(unfeasible_problem_analyzer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering (it's your choice to take this into account) :
We would expect to test an object's behavior (not methods), using it's interface.
We would test simple behaviors, and then more tricky ones.
For example, the names of the tests could be (in the first tests, no need to print a report) :

  • run_analyzer_with_no_analysis (what should we expect in this case ?)
  • run_analyzer_with_one_analysis_detecting_a_pb
  • run_analyzer_with_one_analysis_unable_to_detect_pb
  • run_analyzer_with_2_analyses__none_detects_a_pb
  • run_analyzer_with_2_analyses__only_one_detects_pb
  • run_analyzer_with_2_analyses_detecting_a_pb__only the first_one_is_run
  • what else ?

About printing reports :
@sylvlecl : we just had a chat about it, run() method should produce a report (for example a vector of std::string), either return by run(), or retrievable with a get method.
This would allow to remove the dependency to the logger.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left the test as is to test the actual workflow. I agree that for more important piece of codes we should bother to have finer grained tests though.

{
ConstraintSlackAnalysis analysis;
std::unique_ptr<MPSolver> problem(MPSolver::CreateSolver("GLOP"));
const double inf = problem->infinity();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not hesitate naming infinity "infinity" instead of "inf", which can be confused with inferior

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* - Variable 2 must be lesser than -1
* - but if feasible is false, constraint enforces that variable 2 is greater than variable 1 --> infeasible
*/
std::unique_ptr<MPSolver> createProblem(const std::string& constraintName, bool feasible)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling createProblem() like this createProblem(constraintName, false); is a bit unclear.
A solution could be to have 3 functions :

  • std::unique_ptr<MPSolver> createSimpleProblem()
  • void createFeasibleProblem(MPSolver* pb)
  • void createUnfeasibleProblem(MPSolver* pb)

The last 2 functions would call the first for for the creation a problem with one constraint of 2 variables.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I provided the 2 methods createFeasible and createUnfeasible which just call the initial one.

"AreaHydroLevel::hour<8>",
};

BOOST_DATA_TEST_CASE(test_slack_variables_with_unfeasible_constraint, bdata::make(validConstraintNames), constraintName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test_ prefix not needed.
This test name does not really reflects what it does.
What it does is :
slack variable analysis detects unfeasibility on many well names constraints.
A bit long, but much clearer.

BOOST_CHECK(analysis.hasDetectedInfeasibilityCause());
}

BOOST_AUTO_TEST_CASE(test_slack_variables_with_unfeasible_constraint_name_ignored)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A name could be :
slack variable analysis does not detect unfeasibilty on ill-named constraint

BOOST_CHECK(!analysis.hasDetectedInfeasibilityCause());
}

BOOST_DATA_TEST_CASE(test_slack_variables_no_problematic_constraint, bdata::make(validConstraintNames), constraintName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to parameterize a test for an analysis that won't detect anything ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not very useful indeed, a little redundant with the other test case, I removed the parameterization.

Copy link

sonarqubecloud bot commented Nov 3, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

@sylvlecl sylvlecl merged commit a9c4ad7 into feature/add_check_in_unfeasible_analyzer Nov 3, 2023
@sylvlecl sylvlecl deleted the feature/add_check_in_unfeasible_analyzer_unit_tests branch November 3, 2023 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants