-
Notifications
You must be signed in to change notification settings - Fork 205
Stupid mock assertions in tests #472
Comments
Hi @cezarypiatek - Assert-MockCalled can definitely get a bit out-of-hand and agree that it takes us into testing implementation. However, in some functions it is required as there is no other way to validate the behavior (especially if it is changing the system). That said, just checking a mock is called without validating the parameters it was called with isn't ideal either. So the above mock assertions definitely look like they could be improved. Some guidance could definitely be used here. E.g. I would only be making assertions over the calls that actually change the system state - not worrying about the commands that are returning info. E.g. the example above really should be something like: It 'Should call all the mocks' {
Assert-MockCalled -CommandName Add-WebConfiguration -Exactly -Times 1 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Update-WebsiteBinding -Exactly -Times 1 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Update-DefaultPage -Exactly -Times 1 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Set-Authentication -Exactly -Times 4 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Set-Item -Exactly -Times 3 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Set-ItemProperty -Exactly -Times 9 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Start-Website -Exactly -Times 1 -ParameterFilter { ... TBC ...}
Assert-MockCalled -CommandName Set-WebConfigurationProperty -Exactly -Times 2 -ParameterFilter { ... TBC ...}
} That said, based on these assertions alone, I'd argue that this function is probably in serious need of refactoring - as it is "doing too much". But I guess that is what you're saying: refactoring is expensive due to this problem. tl;dr; Agreed - need some guidelines in place. @johlju - your thoughts? |
I think I'm don't agree that we should remove assert calls. Not sure how we can add this to the guidelines since there are so many edge cases. Suggestions on that? The problem in xWebSite might be that some code should be made into helper functions, and those helper functions should be mocked instead. Although, the helper functions should be tested as well, but separate so there can be less code in the main unit test for xWebSite. 🤔 |
This issue has been automatically marked as stale because it has not had activity from the community in the last 30 days. It will be closed if no further activity occurs within 10 days. If the issue is labelled with any of the work labels (e.g bug, enhancement, documentation, or tests) then the issue will not auto-close. |
I think this discussion should stay open as some guidance would be good. Might also be an opportunity for a decent blog post - when to Mock with parameters and when to not Mock with parameters. |
To summarise:
Call to Actions
|
One more observation: DO NOT use |
One more issue: there is a lot of mocking of module internal methods. I think only module external methods should be mocked. Mocking module internal methods undermine test credibility. |
Most of the tests currently looks as follows:
Why not to write test according to this pattern:
|
@cezarypiatek, I agree in many situations, but definitely not all: If an internal function changes state of the system then it should be mocked. It is generally a good design pattern to separate lower level abstraction functions (functions that change state) into their own function to make mocking easier and to meet single responsibility principle (SRP/SOLID). So, mocking those sorts of internal functions and asserting that they was called I is acceptable. An example: When there isn't a built in Cmdlet that performed the desired state change and so an "internal" function needs to be created to perform the work - e.g. "Set-PowerPlan". It is absolutely acceptable to Mock the Set-PowerPlan function when testing Set-TargetResource even though it is an internal function. I want to test Set-TargetResource, not the implementation of Set-PowerPlan. The key for me is that the tests validate the function and the same level of abstraction. If the function under test is a "logical" layer (e.g. Set-TargetResource) then it should mock all functions calling into the "physical" layer. Tests should validate the behavior of the function under test, and not necessarily the implementation of the "physical" layer as this may be done different ways. Not being able to Mock the physical layer implementation results in brittle tests. But otherwise I agree with you and I have seen situations (and even written them) where in hind-sight I shouldn't have. |
There is a lot of stupid assertions in tests which test implementation details instead of behavior. It doesn't add any value but only makes refactoring harder and bloats the tests code (for example
MSFT_xWebsiteTests.ps1
has almost 4k lines of code, it's really hard to manage that)Example:
I would like to propose to delete all that assertions add mention it as a bad practice in the Contribution guideline.
The text was updated successfully, but these errors were encountered: