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.9.1 #28

Merged
merged 14 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.8.0
default: 1.9.1
VersionSuffix:
type: string
description: The version suffix of the library (for example rc.1)
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,6 @@ FodyWeavers.xsd

# JetBrains Rider
*.sln.iml

# Specific
/tests/Moq.Analyzers.Sandbox/Sandbox.cs
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

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

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
3 changes: 3 additions & 0 deletions PosInformatique.Moq.Analyzers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compilation", "Compilation"
docs\Compilation\PosInfoMoq2006.md = docs\Compilation\PosInfoMoq2006.md
docs\Compilation\PosInfoMoq2007.md = docs\Compilation\PosInfoMoq2007.md
docs\Compilation\PosInfoMoq2008.md = docs\Compilation\PosInfoMoq2008.md
docs\Compilation\PosInfoMoq2009.md = docs\Compilation\PosInfoMoq2009.md
docs\Compilation\PosInfoMoq2010.md = docs\Compilation\PosInfoMoq2010.md
docs\Compilation\PosInfoMoq2011.md = docs\Compilation\PosInfoMoq2011.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
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Design rules used to make your unit tests more strongly strict.
| Rule | Description |
| - | - |
| [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. |
| [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`. |
| [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`. |
| [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. |
Expand All @@ -41,13 +41,16 @@ All the rules of this category should not be disabled (or changed their severity
| - | - |
| [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. |
| [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. |
| [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. |
| [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. |
| [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. |
| [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. |
| [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. |
| [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 |
| [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 |
| [PosInfoMoq2011: Constructor of the mocked class must be accessible.](docs/Compilation/PosInfoMoq2011.md) | The constructor of the instantiate mocked class must non-private. |



40 changes: 40 additions & 0 deletions docs/Compilation/PosInfoMoq2009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# PosInfoMoq2009: `Mock.Of<T>` method must be used only to mock non-sealed class

| Property | Value |
|-------------------------------------|---------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2009 |
| **Title** | `Mock.Of<T>` method must be used only to mock non-sealed class |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The `Mock.Of<T>` method must be used only to mock non-sealed class.

## Rule description

The `Mock.Of<T>` method must be use only on the interfaces or non-`sealed` classes.

For example, the following code can not mock the `Service` class because it is `sealed`.

```csharp
[Fact]
public void Test()
{
var service = Mock.Of<Service>(s => s.Property == 1234); // The Service can not be mocked, because it is a sealed class.
}

public class Service
{
public virtual int Property { get; }
}
```

## How to fix violations

To fix a violation of this rule, be sure to mock interfaces or non-sealed classes.

## 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 `MoqException`
thrown with the *"Type to mock (xxx) must be an interface, a delegate, or a non-selead, non-static class"* message.
65 changes: 65 additions & 0 deletions docs/Compilation/PosInfoMoq2010.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# PosInfoMoq2010: `Mock.Of<T>` method must be used only with types that contains parameterless contructor

| Property | Value |
|-------------------------------------|---------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2010 |
| **Title** | `Mock.Of<T>` method must be used only with types that contains parameterless contructor. |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

The `Mock.Of<T>` method must be used only with types that contains accessible parameterless constructor.

## Rule description

The `Mock.Of<T>` method must be use only for non-`sealed` classes which contains accessible parameterless constructor.

For example, the following code can not mock the `Service` class because it does not contain a parameterless constructor.

```csharp
[Fact]
public void Test()
{
var service = Mock.Of<Service>(s => s.Property == 1234); // The Service can not be mocked, because not parameterless constructor exists.
}

public class Service
{
public Service(int timeout)
{
}

public virtual int Property { get; }
}
```

In this other example, the `Service` class cannot be mocked too because it contains a private constructor.

```csharp
[Fact]
public void Test()
{
var service = Mock.Of<Service>(); // The Service can not be mocked, because the parameterless constructor is private.
}

public class Service
{
private Service()
{
}

public virtual int Property { get; }
}
```

## How to fix violations

To fix a violation of this rule, be sure to the mocked type contains an accessible parameterless constructor
(`public`, `protected` or `internal`)

## 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 not instantiate proxy of class: xxx.
Could not find a parameterless constructor. (Parameter 'constructorArguments')"* message.
46 changes: 46 additions & 0 deletions docs/Compilation/PosInfoMoq2011.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# PosInfoMoq2011: Constructor of the mocked class must be accessible.

| Property | Value |
|-------------------------------------|-------------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq2011 |
| **Title** | Constructor of the mocked class must be accessible. |
| **Category** | Compilation |
| **Default severity** | Error |

## Cause

Constructor of the mocked class must be accessible (`public`, `protected` or `internal`)

## Rule description

The mocked class must not contain an inaccessible constructor.

```csharp
[Fact]
public void Test()
{
var service1 = new Mock<Service>("Hello"); // The constructor invoked is private.
var service2 = new Mock<Service>("Argument 1", 2); // OK
var service3 = new Mock<Service>(MockBehavior.Strict, "Argument 1", 2); // OK
}

public abstract class Service
{
private Service(string a)
{
}

public Service(string a, int b)
{
}
}
```

## How to fix violations

To fix a violation of this rule, be sure to call a non-private constructor when instantiate a mocked 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 `NotSupportedException`
thrown with the *"Parent does not have a default constructor. The default constructor must be explicitly defined."* message.
Binary file added docs/Design/PosInfoMoq1001-Fixer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 26 additions & 5 deletions docs/Design/PosInfoMoq1001.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# PosInfoMoq1001: The `Mock<T>` instance behavior should be defined to Strict mode
# PosInfoMoq1001: The mocked instances behavior should be defined to `Strict` mode

| Property | Value |
|-------------------------------------|------------------------------------------------------------------|
| **Rule ID** | PosInfoMoq1001 |
| **Title** | The `Mock<T>` instance behavior should be defined to Strict mode |
| **Title** | The mocked instances behavior should be defined to `Strict` mode |
| **Category** | Design |
| **Default severity** | Warning |

## Cause

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

## Rule description

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

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

Expand Down Expand Up @@ -78,9 +78,30 @@ public void GetDataFromRepository()
}
```

The same behavior should be defined if the `Mock.Of<T>()` alternative is used:
```csharp
[Fact]
public void GetDataFromRepository()
{
// Arrange
var repository = Mock.Of<IRepository>(MockBehavior.Strict); // Strict behavior (Loose)

// /!\ No methods on the IRepository has been setup !

var service = new CustomerService(repository);

// Act
var result = service.GetDataFromRepository(); // A "MoqException" will be raised to indicate that the GetData() method has not been setup !
}
```

## How to fix violations

To fix a violation of this rule, set the `MockBehavior` to `Strict` in the constructor of the `Mock<T>` class.
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.

### Visual Studio fixer
A Visual Studio fixer exists to set explicitely the `MockBehavior` to `Strict` in the current document, project or solution.
![Visual Studio rule fixer](PosInfoMoq1001-Fixer.png)

## When to suppress warnings

Expand Down
11 changes: 10 additions & 1 deletion src/Moq.Analyzers/AnalyzerReleases.Shipped.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
## Release 1.8.0
## Release 1.9.1

### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
PosInfoMoq2009 | Compilation | Error | `Mock.Of<T>` method must be used only to mock non-sealed class.
PosInfoMoq2010 | Compilation | Error | `Mock.Of<T>` method must be used only with types that contains parameterless contructor.
PosInfoMoq2011 | Compilation | Error | Constructor of the mocked class must be accessible.

## Release 1.8.0

### New Rules

Expand Down
Loading