test(discord): Add null-guard branch coverage for BotService constructor#377
test(discord): Add null-guard branch coverage for BotService constructor#377github-actions[bot] wants to merge 5 commits into
Conversation
| TargetInvocationException ex = Assert.Throws<TargetInvocationException>(() => | ||
| ctor.Invoke([null, messageChannel, releaseChannel]) | ||
| ); | ||
| Assert.IsType<ArgumentNullException>(ex.InnerException); |
There was a problem hiding this comment.
[Code Review] The test asserts only IsType<ArgumentNullException> without checking ParamName. If the guard in BotService is accidentally changed to throw new ArgumentNullException(nameof(botMessageChannel)) (wrong parameter name), the test still passes and the regression goes undetected.
Suggestion: also assert the parameter name:
ArgumentNullException ane = Assert.IsType<ArgumentNullException>(ex.InnerException);
Assert.Equal("bot", ane.ParamName);There was a problem hiding this comment.
Fixed in 0e24809 — asserted ParamName == "bot" on the caught ArgumentNullException so a mis-targeted guard would be detected.
| MessageChannel<BotMessage> messageChannel = new(); | ||
| MessageChannel<BotReleaseMessage> releaseChannel = new(); | ||
|
|
||
| ConstructorInfo ctor = Assert.Single(typeof(BotService).GetConstructors()); |
There was a problem hiding this comment.
[Code Review] Assert.Single(typeof(BotService).GetConstructors()) is a guard against a second constructor being added, but if one is ever added the failure message will be a count-related xunit error with no mention of null guards — making the root cause non-obvious to the next developer.
Consider selecting the specific constructor by its parameter types instead, which both locates the right overload and provides a clearer failure if the signature changes:
ConstructorInfo? ctor = typeof(BotService).GetConstructor([
typeof(IDiscordBot),
typeof(IMessageChannel<BotMessage>),
typeof(IMessageChannel<BotReleaseMessage>)
]);
Assert.NotNull(ctor);There was a problem hiding this comment.
Fixed in 0e24809 — replaced Assert.Single(GetConstructors()) with GetConstructor([...]) targeting the constructor by explicit parameter types, giving a clearer failure if the signature changes.
| [Fact] | ||
| public void Constructor_ThrowsArgumentNullException_WhenBotIsNull() | ||
| { | ||
| MessageChannel<BotMessage> messageChannel = new(); |
There was a problem hiding this comment.
[Code Review] messageChannel and releaseChannel are created but never reached: the BotService constructor throws ArgumentNullException on the first line (bot ?? throw ...) before it touches either channel parameter. Passing null for those positions (or any placeholder) would produce the same result and make it clearer that only bot is the subject under test.
There was a problem hiding this comment.
Fixed in 0e24809 — removed the unnecessary messageChannel and releaseChannel allocations; all three invoke arguments are now null since the constructor throws before reaching the channel parameters.
|
[Code Review — Pre-existing gap] |
- Use GetConstructor with explicit parameter types instead of Assert.Single on GetConstructors(), avoiding confusing failure messages if a second constructor is ever added - Remove unnecessary MessageChannel allocations — the constructor throws before touching the channel parameters, so null suffices for those args - Assert ParamName == "bot" on the caught ArgumentNullException so a mis-targeted guard is detected rather than silently passing Prompt: Work on pull request #377 in funfair-tech/BuildBot.
- Use GetConstructor with explicit parameter types instead of Assert.Single on GetConstructors(), avoiding confusing failure messages if a second constructor is ever added - Remove unnecessary MessageChannel allocations — the constructor throws before touching the channel parameters, so null suffices for those args - Assert ParamName == "bot" on the caught ArgumentNullException so a mis-targeted guard is detected rather than silently passing Prompt: Work on pull request #377 in funfair-tech/BuildBot.
b04c00f to
c2aa353
Compare
- Use GetConstructor with explicit parameter types instead of Assert.Single on GetConstructors(), avoiding confusing failure messages if a second constructor is ever added - Remove unnecessary MessageChannel allocations — the constructor throws before touching the channel parameters, so null suffices for those args - Assert ParamName == "bot" on the caught ArgumentNullException so a mis-targeted guard is detected rather than silently passing Prompt: Work on pull request #377 in funfair-tech/BuildBot.
c2aa353 to
0e24809
Compare
…nstructor Add `?? throw ArgumentNullException` guards for botMessageChannel and botReleaseMessageChannel — they were assigned without guards and would cause a NullReferenceException deep in Rx internals if passed null. Add corresponding constructor tests to cover both new guards. Prompt: Work on pull request #377 in funfair-tech/BuildBot.
…structor Prompt: Work on pull request #377 in funfair-tech/BuildBot.
|
Fixed in ee1e59b — added |
| } | ||
|
|
||
| [Fact] | ||
| public void Constructor_ThrowsArgumentNullException_WhenBotIsNull() |
There was a problem hiding this comment.
[Code Review] The three Constructor_ThrowsArgumentNullException_When* methods are structurally identical — each performs the same GetConstructor lookup and the same assert pattern, varying only in which argument is null and the expected ParamName. Project rules require: 'Prefer parameterised tests over duplicated test methods — each behavioural variant is a data point, not a separate method. Use the idiomatic mechanism for the framework (xUnit [Theory]/[InlineData]).' A single [Theory] with [MemberData] covers all three cases, and also eliminates the GetConstructor call duplicated verbatim three times.
There was a problem hiding this comment.
Fixed in bf6ec38 — collapsed the three identical [Fact] methods into a single [Theory] with [MemberData], using an int index to select which parameter is null and setting it after pre-populating all args with non-null substitutes. The GetConstructor call now appears once.
Replace three structurally identical Constructor_ThrowsArgumentNullException_When* [Fact] methods with a single [Theory] + [MemberData] test, using an index to select which parameter is null. Removes the GetConstructor call duplicated verbatim three times and satisfies the project rule requiring parameterised tests over duplicated methods. Prompt: Work on pull request #377 in funfair-tech/BuildBot.
Super-linter summary
All files and directories linted successfully For more information, see the GitHub Actions workflow run Powered by Super-linter |
|
All work complete. Summary of changes on this PR:
Code review and security review both passed clean. Auto-merge enabled. |
Adds a reflection-based test to cover the null-bot argument guard in BotService, bringing BotService to 100% line and branch coverage. The null! operator cannot be used directly due to the NX0002 analyser rule, so the constructor is invoked via reflection. Prompt: Work on issue #356 in funfair-tech/BuildBot. Closes #356
- Use GetConstructor with explicit parameter types instead of Assert.Single on GetConstructors(), avoiding confusing failure messages if a second constructor is ever added - Remove unnecessary MessageChannel allocations — the constructor throws before touching the channel parameters, so null suffices for those args - Assert ParamName == "bot" on the caught ArgumentNullException so a mis-targeted guard is detected rather than silently passing Prompt: Work on pull request #377 in funfair-tech/BuildBot.
…nstructor Add `?? throw ArgumentNullException` guards for botMessageChannel and botReleaseMessageChannel — they were assigned without guards and would cause a NullReferenceException deep in Rx internals if passed null. Add corresponding constructor tests to cover both new guards. Prompt: Work on pull request #377 in funfair-tech/BuildBot.
…structor Prompt: Work on pull request #377 in funfair-tech/BuildBot.
Replace three structurally identical Constructor_ThrowsArgumentNullException_When* [Fact] methods with a single [Theory] + [MemberData] test, using an index to select which parameter is null. Removes the GetConstructor call duplicated verbatim three times and satisfies the project rule requiring parameterised tests over duplicated methods. Prompt: Work on pull request #377 in funfair-tech/BuildBot.
bf6ec38 to
3f41659
Compare
|
Rebased the branch onto |
|
All CI checks pass and auto-merge is enabled. The PR is currently blocked on |
Summary
bot == nullguard inBotServiceconstructor, bringingBotServiceto 100% line and branch coverage.null!directly, so the constructor is invoked viaConstructorInfo.Invokewith a null argument instead.Coverage status after this PR
Remaining gaps in
BuildBot.Discord(DiscordChannelAdapterand the live-infrastructure methods ofDiscordSocketClientAdapter) are infrastructure-dependent and tracked in issue #374.Closes #356
Test plan
BotServicereaches 100% line and branch coveragedotnet buildcheckpasses with no errors