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

v1.11.0 #43

Merged
merged 15 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/github-actions-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
type: string
description: The version of the library
required: true
default: 1.10.0
default: 1.11.0
VersionSuffix:
type: string
description: The version suffix of the library (for example rc.1)
Expand Down
4 changes: 4 additions & 0 deletions PosInformatique.Moq.Analyzers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Design", "Design", "{815BE8
docs\Design\PosInfoMoq1002.md = docs\Design\PosInfoMoq1002.md
docs\Design\PosInfoMoq1003.md = docs\Design\PosInfoMoq1003.md
docs\Design\PosInfoMoq1004.md = docs\Design\PosInfoMoq1004.md
docs\Design\PosInfoMoq1005.md = docs\Design\PosInfoMoq1005.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compilation", "Compilation", "{D9C84D36-7F9C-4EFB-BE6F-9F7A05FE957D}"
Expand All @@ -51,6 +52,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compilation", "Compilation"
docs\Compilation\PosInfoMoq2011.md = docs\Compilation\PosInfoMoq2011.md
docs\Compilation\PosInfoMoq2012.md = docs\Compilation\PosInfoMoq2012.md
docs\Compilation\PosInfoMoq2013.md = docs\Compilation\PosInfoMoq2013.md
docs\Compilation\PosInfoMoq2014.md = docs\Compilation\PosInfoMoq2014.md
docs\Compilation\PosInfoMoq2015.md = docs\Compilation\PosInfoMoq2015.md
docs\Compilation\PosInfoMoq2016.md = docs\Compilation\PosInfoMoq2016.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers.Sandbox", "tests\Moq.Analyzers.Sandbox\Moq.Analyzers.Sandbox.csproj", "{07F970A1-1477-4D4C-B233-C9B4DA6E3AD6}"
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Design rules used to make your unit tests more strongly strict.
| [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. |
| [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. |
| [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. |
| [PosInfoMoq1005: Defines the generic argument of the `SetupSet()` method with the type of the mocked property](docs/Design/PosInfoMoq1005.md) | When mocking the setter of a property, use the `SetupSet<TProperty>()` method version. |

### Compilation

Expand All @@ -40,7 +41,7 @@ All the rules of this category should not be disabled (or changed their severity
| Rule | Description |
| - | - |
| [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. |
| [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. |
| [PosInfoMoq2001: The `Setup()`/`SetupSet()` method must be used only on overridable members](docs/Compilation/PosInfoMoq2001.md)) | The `Setup()` method must be applied only for overridable members. |
| [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. |
| [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. |
| [PosInfoMoq2004: Constructor arguments cannot be passed for interface mocks](docs/Compilation/PosInfoMoq2004.md) | No arguments can be passed to a mocked interface. |
Expand All @@ -53,6 +54,9 @@ All the rules of this category should not be disabled (or changed their severity
| [PosInfoMoq2011: Constructor of the mocked class must be accessible.](docs/Compilation/PosInfoMoq2011.md) | The constructor of the instantiate mocked class must non-private. |
| [PosInfoMoq2012: The delegate in the argument of the `Returns()` method must return a value with same type of the mocked method.](docs/Compilation/PosInfoMoq2012.md) | The lambda expression, anonymous method or method in the argument of the `Returns()` must return return a value of the same type as the mocked method or property. |
| [PosInfoMoq2013: The delegate in the argument of the `Returns()`/`ReturnsAsync()` method must have the same parameter types of the mocked method/property.](docs/Compilation/PosInfoMoq2013.md) | The lambda expression, anonymous method or method in the argument of the `Returns()`/`ReturnsAsync()` must have the same arguments type of the mocked method or property. |
| [PosInfoMoq2014: The `Callback()` delegate expression must not return a value.](docs/Compilation/PosInfoMoq2014.md) | The `Callback()` delegate expression must not return a value. |
| [PosInfoMoq2015: The `Protected().Setup()` method must match the return type of the mocked method](docs/Compilation/PosInfoMoq2015.md) | The method setup with `Protected().Setup()` must match the return type of the mocked method. |
| [PosInfoMoq2016: `Mock<T>` constructor with factory lambda expression can be used only with classes.](docs/Compilation/PosInfoMoq2016.md) | The factory lambda expression used in `Mock<T>` instantiation must used only for the classes. |



27 changes: 16 additions & 11 deletions docs/Compilation/PosInfoMoq2001.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# PosInfoMoq2001: The `Setup()` method must be used only on overridable members
# PosInfoMoq2001: The `Setup()`/`SetupSet()` method must be used only on overridable members

| Property | Value |
|-------------------------------------|---------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2001 |
| **Title** | The `Setup()` method must be used only on overridable members |
| **Title** | The `Setup()`/`SetupSet()` method must be used only on overridable members |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The `Setup()` method must be applied only for overridable members.
The `Setup()` or `SetupSet()` methods must be applied only for overridable members.
An overridable member is a **method** or **property** which is in:
- An `interface`.
- A non-`sealed` `class`. In this case, the member must be:
Expand All @@ -20,13 +20,18 @@ An overridable member is a **method** or **property** which is in:

The `Setup()` method must be applied only for overridable members.

For example, the following methods and properties can be mock and used in the `Setup()` method:
- `IService.MethodCanBeMocked()`
- `IService.PropertyCanBeMocked`
- `Service.VirtualMethodCanBeMocked`
- `Service.VirtualPropertyCanBeMocked`
- `Service.AbstractMethodCanBeMocked`
- `Service.AbstractPropertyCanBeMocked`
For example:
- The following methods and properties can be mock and used in the `Setup()` method:
- `IService.MethodCanBeMocked()`
- `IService.PropertyCanBeMocked`
- `Service.VirtualMethodCanBeMocked`
- `Service.VirtualPropertyCanBeMocked`
- `Service.AbstractMethodCanBeMocked`
- `Service.AbstractPropertyCanBeMocked`
- The following properties can be mock and used in the `SetupSet()` method:
- `IService.PropertyCanBeMocked`
- `Service.VirtualPropertyCanBeMocked`
- `Service.AbstractPropertyCanBeMocked`

```csharp
public interface IService
Expand All @@ -53,7 +58,7 @@ static methods which can not be overriden.

## How to fix violations

To fix a violation of this rule, be sure to mock a member in the `Setup()` method which can be overriden.
To fix a violation of this rule, be sure to mock a member in the `Setup()` or `SetupSet()` method which can be overriden.

## When to suppress warnings

Expand Down
2 changes: 1 addition & 1 deletion docs/Compilation/PosInfoMoq2006.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ and must be overridable (`virtual`, `abstract` and `override`, but not `sealed`)
public void Test()
{
var service = new Mock<Service>();
service.Protected().Setup("GetData") // The GetData() is public and can be mocked with Protected() feature.
service.Protected().Setup("GetData") // The GetData() is public and can't be mocked with Protected() feature.
.Returns(10);
service.Protected().Setup("NotExists") // The NotExists() method does not exist.
.Returns(10);
Expand Down
45 changes: 45 additions & 0 deletions docs/Compilation/PosInfoMoq2014.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# PosInfoMoq2014: The `Callback()` delegate expression must not return a value.

| Property | Value |
|-------------------------------------|-----------------------------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2014 |
| **Title** | The `Callback()` delegate expression must not return a value. |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The delegate in the argument of the `Callback()` method must not return a value.

## Rule description

The lambda expression in the argument of the `Callback()` method must not return a value.

```csharp
[Fact]
public void Test()
{
var service = new Mock<Service>();
service.Setup(s => s.GetData("TOURREAU", 1234))
.Callback((string n, int age) =>
{
// ...
return 1234; // The delegate in the Callback() method must not return a value.
})
.Returns(10);
}

public interface IService
{
public int GetData(string name, int age) { }
}
```

## How to fix violations

To fix a violation of this rule, be sure that the delegate method in the `Callback()` method does not return a value.

## When to suppress warnings

Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `ArgumentException`
thrown with the *"Invalid callback. This overload of the "Callback" method only accepts "void" (C#) or "Sub" (VB.NET) delegates with parameter types matching those of the set up method. (Parameter 'callback')"* message.
50 changes: 50 additions & 0 deletions docs/Compilation/PosInfoMoq2015.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# PosInfoMoq2015: The `Protected().Setup()` method must match the return type of the mocked method

| Property | Value |
|-------------------------------------|----------------------------------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2015 |
| **Title** | The `Protected().Setup()` method must match the return type of the mocked method. |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The method setup with `Protected().Setup()` must match the return type of the mocked method.

## Rule description

When using the `Protected().Setup()`, the return type of mocked method must match of the generic
argument specified in the `Setup<T>()` method.

```csharp
[Fact]
public void Test()
{
var service = new Mock<Service>();
service.Protected().Setup<int>("GetData") // OK.
.Returns(10);
service.Protected().Setup("GetData") // Error: The GetData() return an int, Setup<int>() must be use.
service.Protected().Setup<int>("SendEmail") // Error: The SendEmail() method does not return a value, the `int` generic argument must be remove.0
.Returns(10);
service.Protected().Setup<string>("GetData") // Error: The GetData() return an int, Setup<int>() must be use.
.Returns("The data");
}

public abstract class Service
{
protected abstract int GetData();

protected abstract void SendEmail();
}
```

## How to fix violations

To fix a violation of this rule, use the generic parameter of the `Setup<T>()` method if the protected mocked
method return a value. Else do not specify a generic parameter for the `Setup<T>()` method of the protected mocked
method does not return a value (`void`).

## When to suppress warnings

Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `ArgumentException`
thrown with the *"Can't set return value for void method xxx."* message.
45 changes: 45 additions & 0 deletions docs/Compilation/PosInfoMoq2016.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# PosInfoMoq2016: `Mock<T>` constructor with factory lambda expression can be used only with classes.

| Property | Value |
|-------------------------------------|-------------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2016 |
| **Title** | `Mock<T>` constructor with factory lambda expression can be used only with classes. |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The factory lambda expression used in `Mock<T>` instantiation must used only for the classes.

## Rule description

When using a lambda expression in the constructor of Mock<T> to create a mock instance, the mocked type must be a class.

```csharp
[Fact]
public void Test()
{
var service1 = new Mock<IService>(() => new Service()); // The factory lambda expression can be used only on classes type.
var service2 = new Mock<Service>(() => new Service()); // OK
}

public interface IService
{
}

public class Service : IService:
{
public Service(string a)
{
}
}
```

## How to fix violations

To fix a violation of this rule, ensure that the lambda expression factory is used with a mocked type that is a class.

## When to suppress warnings

Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `ArgumentException`
thrown with the *"Constructor arguments cannot be passed for interface mocks."* message.
Binary file added docs/Design/PosInfoMoq1005-Fixer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions docs/Design/PosInfoMoq1005.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# PosInfoMoq1005: Defines the generic argument of the `SetupSet()` method with the type of the mocked property.

| Property | Value |
|-------------------------------------|------------------------------------------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq1005 |
| **Title** | Defines the generic argument of the `SetupSet()` method with the type of the mocked property. |
| **Category** | Design |
| **Default severity** | Warning |

## Cause

A property setter has been set up using `SetupSet()` without a generic argument that represents the type of the mocked property.

## Rule description

Moq provides two methods to mock a property setter:
- `Mock<T>.SetupSet(Action<T>)`
- `Mock<T>.SetupSet<TProperty>(Action<T, TProperty>)`

When setting up a property setter, use `Mock<T>.SetupSet<TProperty>(Action<T, TProperty>)` by explicitly defining the type of the property to mock.
This overload of the `SetupSet()` method allows you to define a typed `Callback()` and avoid exceptions if the delegate argument in the `Callback()`
does not match the property type.

For example, consider the following code to test:

```csharp
[Fact]
public interface Customer
{
string Name { get; set; }
}
```

If you mock the setter of the `Customer.Name` property, you should set up the property with the `SetupSet<string>()` method:

```csharp
[Fact]
public void SetNameOfCustomer()
{
var customer = new Mock<Customer>();
customer.SetupSet<string>(c => c.Name = "Gilles") // The SetupSet<string>() version is used.
.Callback((string value) =>
{
// Called when the setter of the property is set.
});
}
```

The following code violates the rule because the `SetupSet()` method has no generic argument:

```csharp
[Fact]
public void SetNameOfCustomer()
{
var customer = new Mock<Customer>();
customer.SetupSet(c => c.Name = "Gilles") // The SetupSet() has been used without set the generic argument.
.Callback((string value) =>
{
// Called when the setter of the property is set.
});
}
```

If the non-generic version of the `SetupSet()` method is used, the delegate in the `Callback()` method cannot be checked at compile time,
an exception will occur during the execution of the unit test:

```csharp
[Fact]
public void SetNameOfCustomer()
{
var customer = new Mock<Customer>();
customer.SetupSet(c => c.Name = "Gilles")
.Callback((int value) => // The code compiles, but during the execution of the unit test
{ // an ArgumentException will be thrown.
});
}
```

## How to fix violations

To fix a violation of this rule, use the `SetupSet<TProperty>()` method with the type of the mocked property as the generic argument.

### Visual Studio fixer
A Visual Studio fixer exists to set explicitly the generic argument of the `SetupSet<T>()` method with the property type
in the current document, project or solution.

![Visual Studio rule fixer](PosInfoMoq1005-Fixer.png)

## When to suppress warnings

Do not suppress a warning from this rule. Using the `SetupSet<T>()` method ensures that the delegate argument in the `Callback()`
method matches the type of the property.
12 changes: 11 additions & 1 deletion src/Moq.Analyzers/AnalyzerReleases.Shipped.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
## Release 1.10.0
## Release 1.11.0

### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
PosInfoMoq1005 | Design | Warning | Defines the generic argument of the `SetupSet()` method with the type of the mocked property.
PosInfoMoq2014 | Compilation | Error | The `Callback()` delegate expression must not return a value.
PosInfoMoq2015 | Compilation | Error | The `Protected().Setup()` method must match the return type of the mocked method.
PosInfoMoq2016 | Compilation | Error | `Mock<T>` constructor with factory lambda expression can be used only with classes.

## Release 1.10.0

### New Rules
Rule ID | Category | Severity | Notes
Expand Down
Loading
Loading