Skip to content

Commit d639007

Browse files
v1.9.1 (#28)
* Renames the NoSealedClassAnalyzer to MockClassCanBeUsedOnlyToMockNonSealedClassAnalyzer. * Add the PosInfoMoq2009 rule. * Updates the PosInfoMoq1001 rule to check the Mock.Of<T>() usage (fixes #27). * Change the version number to 1.9.1 * Renames the MockOfCanBeUsedOnlyToMockNonSealedClassAnalyzer to MockOfAnalyzer. * Add the PosInfoMoq2010 rule to check that types for Mock.Of<T>() have parameterless contructor. * Add the PosInfoMoq2011 rule. * Fix the PosInfoMoq2005 rule to check only the class types.
1 parent 282546d commit d639007

26 files changed

Lines changed: 1696 additions & 140 deletions

.github/workflows/github-actions-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
type: string
88
description: The version of the library
99
required: true
10-
default: 1.8.0
10+
default: 1.9.1
1111
VersionSuffix:
1212
type: string
1313
description: The version suffix of the library (for example rc.1)

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,6 @@ FodyWeavers.xsd
396396

397397
# JetBrains Rider
398398
*.sln.iml
399+
400+
# Specific
401+
/tests/Moq.Analyzers.Sandbox/Sandbox.cs

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2023 P.O.S Informatique
3+
Copyright (c) 2023-2024 P.O.S Informatique
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

PosInformatique.Moq.Analyzers.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compilation", "Compilation"
4646
docs\Compilation\PosInfoMoq2006.md = docs\Compilation\PosInfoMoq2006.md
4747
docs\Compilation\PosInfoMoq2007.md = docs\Compilation\PosInfoMoq2007.md
4848
docs\Compilation\PosInfoMoq2008.md = docs\Compilation\PosInfoMoq2008.md
49+
docs\Compilation\PosInfoMoq2009.md = docs\Compilation\PosInfoMoq2009.md
50+
docs\Compilation\PosInfoMoq2010.md = docs\Compilation\PosInfoMoq2010.md
51+
docs\Compilation\PosInfoMoq2011.md = docs\Compilation\PosInfoMoq2011.md
4952
EndProjectSection
5053
EndProject
5154
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers.Sandbox", "tests\Moq.Analyzers.Sandbox\Moq.Analyzers.Sandbox.csproj", "{07F970A1-1477-4D4C-B233-C9B4DA6E3AD6}"

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Design rules used to make your unit tests more strongly strict.
2727
| Rule | Description |
2828
| - | - |
2929
| [PosInfoMoq1000: `VerifyAll()` methods should be called when instantiate a `Mock<T>` instances](docs/Design/PosInfoMoq1000.md) | When instantiating a `Mock<T>` in the *Arrange* phase of an unit test, `VerifyAll()` method should be called in the *Assert* phase to check the setup methods has been called. |
30-
| [PosInfoMoq1001: The `Mock<T>` instance behavior should be defined to Strict mode](docs/Design/PosInfoMoq1001.md) | When instantiating a `Mock<T>` instance, the `MockBehavior` of the `Mock` instance should be defined to `Strict`. |
30+
| [PosInfoMoq1001: The mocked instances behaviors should be defined to `Strict` mode](docs/Design/PosInfoMoq1001.md) | When instantiating a `Mock<T>` instance, the `MockBehavior` of the `Mock` instance should be defined to `Strict`. |
3131
| [PosInfoMoq1002: `Verify()` methods should be called when `Verifiable()` has been setup](docs/Design/PosInfoMoq1002.md) | When a mocked member has been setup with the `Verifiable()` method, the `Verify()` method must be called at the end of the unit test. |
3232
| [PosInfoMoq1003: The `Callback()` method should be used to check the parameters when mocking a method with `It.IsAny<T>()` arguments](docs/Design/PosInfoMoq1003.md) | When a mocked method contains a `It.IsAny<T>()` argument, the related parameter should be checked in the `Callback()` method. |
3333
| [PosInfoMoq1004: The `Callback()` parameter should not be ignored if it has been setup as an `It.IsAny<T>()` argument](docs/Design/PosInfoMoq1004.md) | When a mocked method contains a `It.IsAny<T>()` argument, the related parameter should not be ignored in the `Callback()` method. |
@@ -41,13 +41,16 @@ All the rules of this category should not be disabled (or changed their severity
4141
| - | - |
4242
| [PosInfoMoq2000: The `Returns()` or `ReturnsAsync()` methods must be call for Strict mocks](docs/Compilation/PosInfoMoq2000.md) | When a `Mock<T>` has been defined with the `Strict` behavior, the `Returns()` or `ReturnsAsync()` method must be called when setup a method to mock which returns a value. |
4343
| [PosInfoMoq2001: The `Setup()` method must be used only on overridable members](docs/Compilation/PosInfoMoq2001.md)) | The `Setup()` method must be applied only for overridable members. |
44-
| [PosInfoMoq2002: `Mock<T>` class can be used only to mock non-sealed class](docs/Compilation/PosInfoMoq2002.md) | The `Mock<T>` can mock only interfaces or non-`sealed` classes. |
44+
| [PosInfoMoq2002: `Mock<T>` class can be used only to mock non-sealed class](docs/Compilation/PosInfoMoq2002.md) | The `Mock<T>` class can mock only interfaces or non-`sealed` classes. |
4545
| [PosInfoMoq2003: The `Callback()` delegate expression must match the signature of the mocked method](docs/Compilation/PosInfoMoq2003.md) | The delegate in the argument of the `Callback()` method must match the signature of the mocked method. |
4646
| [PosInfoMoq2004: Constructor arguments cannot be passed for interface mocks](docs/Compilation/PosInfoMoq2004.md) | No arguments can be passed to a mocked interface. |
4747
| [PosInfoMoq2005: Constructor arguments must match the constructors of the mocked class](docs/Compilation/PosInfoMoq2005.md) | When instantiating a `Mock<T>`, the parameters must match one of the constructors of the mocked type. |
4848
| [PosInfoMoq2006: The Protected().Setup() method must be use with overridable protected or internal methods](docs/Compilation/PosInfoMoq2006.md) | When using the `Protected().Setup()` configuration, the method mocked must be overridable and protected or internal. |
4949
| [PosInfoMoq2007: The `As<T>()` method can be used only with interfaces.](docs/Compilation/PosInfoMoq2007.md) | The `As<T>()` can only be use with the interfaces. |
5050
| [PosInfoMoq2008: The `Verify()` method must be used only on overridable members](docs/Compilation/PosInfoMoq2008.md)) | The `Verify()` method must be applied only for overridable members. |
51+
| [PosInfoMoq2009: `Mock.Of<T>` method must be used only to mock non-sealed class](docs/Compilation/PosInfoMoq2009.md) | The `Mock.Of<T>` method can mock only interfaces or non-`sealed` classes |
52+
| [PosInfoMoq2010: `Mock.Of<T>` method must be used only with types that contains parameterless contructor](docs/Compilation/PosInfoMoq2010.md) | The `Mock.Of<T>` method requires a non-private parameterless contructor |
53+
| [PosInfoMoq2011: Constructor of the mocked class must be accessible.](docs/Compilation/PosInfoMoq2011.md) | The constructor of the instantiate mocked class must non-private. |
5154

5255

5356

docs/Compilation/PosInfoMoq2009.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# PosInfoMoq2009: `Mock.Of<T>` method must be used only to mock non-sealed class
2+
3+
| Property | Value |
4+
|-------------------------------------|---------------------------------------------------------------|
5+
| **Rule ID** | PosInfoMoq2009 |
6+
| **Title** | `Mock.Of<T>` method must be used only to mock non-sealed class |
7+
| **Category** | Compilation |
8+
| **Default severity** | Error |
9+
10+
## Cause
11+
12+
The `Mock.Of<T>` method must be used only to mock non-sealed class.
13+
14+
## Rule description
15+
16+
The `Mock.Of<T>` method must be use only on the interfaces or non-`sealed` classes.
17+
18+
For example, the following code can not mock the `Service` class because it is `sealed`.
19+
20+
```csharp
21+
[Fact]
22+
public void Test()
23+
{
24+
var service = Mock.Of<Service>(s => s.Property == 1234); // The Service can not be mocked, because it is a sealed class.
25+
}
26+
27+
public class Service
28+
{
29+
public virtual int Property { get; }
30+
}
31+
```
32+
33+
## How to fix violations
34+
35+
To fix a violation of this rule, be sure to mock interfaces or non-sealed classes.
36+
37+
## When to suppress warnings
38+
39+
Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `MoqException`
40+
thrown with the *"Type to mock (xxx) must be an interface, a delegate, or a non-selead, non-static class"* message.

docs/Compilation/PosInfoMoq2010.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# PosInfoMoq2010: `Mock.Of<T>` method must be used only with types that contains parameterless contructor
2+
3+
| Property | Value |
4+
|-------------------------------------|---------------------------------------------------------------|
5+
| **Rule ID** | PosInfoMoq2010 |
6+
| **Title** | `Mock.Of<T>` method must be used only with types that contains parameterless contructor. |
7+
| **Category** | Compilation |
8+
| **Default severity** | Error |
9+
10+
## Cause
11+
12+
The `Mock.Of<T>` method must be used only with types that contains accessible parameterless constructor.
13+
14+
## Rule description
15+
16+
The `Mock.Of<T>` method must be use only for non-`sealed` classes which contains accessible parameterless constructor.
17+
18+
For example, the following code can not mock the `Service` class because it does not contain a parameterless constructor.
19+
20+
```csharp
21+
[Fact]
22+
public void Test()
23+
{
24+
var service = Mock.Of<Service>(s => s.Property == 1234); // The Service can not be mocked, because not parameterless constructor exists.
25+
}
26+
27+
public class Service
28+
{
29+
public Service(int timeout)
30+
{
31+
}
32+
33+
public virtual int Property { get; }
34+
}
35+
```
36+
37+
In this other example, the `Service` class cannot be mocked too because it contains a private constructor.
38+
39+
```csharp
40+
[Fact]
41+
public void Test()
42+
{
43+
var service = Mock.Of<Service>(); // The Service can not be mocked, because the parameterless constructor is private.
44+
}
45+
46+
public class Service
47+
{
48+
private Service()
49+
{
50+
}
51+
52+
public virtual int Property { get; }
53+
}
54+
```
55+
56+
## How to fix violations
57+
58+
To fix a violation of this rule, be sure to the mocked type contains an accessible parameterless constructor
59+
(`public`, `protected` or `internal`)
60+
61+
## When to suppress warnings
62+
63+
Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `ArgumentException`
64+
thrown with the *"Can not instantiate proxy of class: xxx.
65+
Could not find a parameterless constructor. (Parameter 'constructorArguments')"* message.

docs/Compilation/PosInfoMoq2011.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# PosInfoMoq2011: Constructor of the mocked class must be accessible.
2+
3+
| Property | Value |
4+
|-------------------------------------|-------------------------------------------------------------------------|
5+
| **Rule ID** | PosInfoMoq2011 |
6+
| **Title** | Constructor of the mocked class must be accessible. |
7+
| **Category** | Compilation |
8+
| **Default severity** | Error |
9+
10+
## Cause
11+
12+
Constructor of the mocked class must be accessible (`public`, `protected` or `internal`)
13+
14+
## Rule description
15+
16+
The mocked class must not contain an inaccessible constructor.
17+
18+
```csharp
19+
[Fact]
20+
public void Test()
21+
{
22+
var service1 = new Mock<Service>("Hello"); // The constructor invoked is private.
23+
var service2 = new Mock<Service>("Argument 1", 2); // OK
24+
var service3 = new Mock<Service>(MockBehavior.Strict, "Argument 1", 2); // OK
25+
}
26+
27+
public abstract class Service
28+
{
29+
private Service(string a)
30+
{
31+
}
32+
33+
public Service(string a, int b)
34+
{
35+
}
36+
}
37+
```
38+
39+
## How to fix violations
40+
41+
To fix a violation of this rule, be sure to call a non-private constructor when instantiate a mocked class.
42+
43+
## When to suppress warnings
44+
45+
Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `NotSupportedException`
46+
thrown with the *"Parent does not have a default constructor. The default constructor must be explicitly defined."* message.
24.3 KB
Loading

docs/Design/PosInfoMoq1001.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# PosInfoMoq1001: The `Mock<T>` instance behavior should be defined to Strict mode
1+
# PosInfoMoq1001: The mocked instances behavior should be defined to `Strict` mode
22

33
| Property | Value |
44
|-------------------------------------|------------------------------------------------------------------|
55
| **Rule ID** | PosInfoMoq1001 |
6-
| **Title** | The `Mock<T>` instance behavior should be defined to Strict mode |
6+
| **Title** | The mocked instances behavior should be defined to `Strict` mode |
77
| **Category** | Design |
88
| **Default severity** | Warning |
99

1010
## Cause
1111

12-
A Mock<T> instance has been created with the `Loose` behavior instead of `Strict`.
12+
A mocked instance has been created with the `Loose` or `Default` behavior instead of `Strict`.
1313

1414
## Rule description
1515

16-
When instantiating a `Mock<T>` instance, the `MockBehavior` of the `Mock` instance should be defined to `Strict`.
16+
When instantiating a `Mock<T>` instance (or using the `Mock.Of<T>()` alternative), the `MockBehavior` of the `Mock` instance should be defined to `Strict`.
1717

1818
By default, [Moq](https://github.com/devlooped/moq) build instances of mocked instance which have a `Loose` behavior for non-setup methods.
1919

@@ -78,9 +78,30 @@ public void GetDataFromRepository()
7878
}
7979
```
8080

81+
The same behavior should be defined if the `Mock.Of<T>()` alternative is used:
82+
```csharp
83+
[Fact]
84+
public void GetDataFromRepository()
85+
{
86+
// Arrange
87+
var repository = Mock.Of<IRepository>(MockBehavior.Strict); // Strict behavior (Loose)
88+
89+
// /!\ No methods on the IRepository has been setup !
90+
91+
var service = new CustomerService(repository);
92+
93+
// Act
94+
var result = service.GetDataFromRepository(); // A "MoqException" will be raised to indicate that the GetData() method has not been setup !
95+
}
96+
```
97+
8198
## How to fix violations
8299

83-
To fix a violation of this rule, set the `MockBehavior` to `Strict` in the constructor of the `Mock<T>` class.
100+
To fix a violation of this rule, set the `MockBehavior` to `Strict` in the constructor of the `Mock<T>` class or as the last argument of `Mock.Of<T>()` method.
101+
102+
### Visual Studio fixer
103+
A Visual Studio fixer exists to set explicitely the `MockBehavior` to `Strict` in the current document, project or solution.
104+
![Visual Studio rule fixer](PosInfoMoq1001-Fixer.png)
84105

85106
## When to suppress warnings
86107

0 commit comments

Comments
 (0)