├── .github ├── FUNDING.yml └── workflows │ └── dotnetcore.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md └── src └── MockQueryable ├── Assets ├── logo-github.png └── logo.png ├── MockQueryable.Core ├── Assets │ └── logo.png ├── MockQueryable.Core.csproj ├── TestExpressionVisitor.cs └── TestQueryProvider.cs ├── MockQueryable.EntityFrameworkCore ├── Assets │ └── logo.png ├── MockQueryable.EntityFrameworkCore.csproj ├── TestAsyncEnumerator.cs └── TestQueryProviderEfCore.cs ├── MockQueryable.FakeItEasy ├── Assets │ └── logo.png ├── FakeItEasyExtensions.cs └── MockQueryable.FakeItEasy.csproj ├── MockQueryable.Moq ├── Assets │ └── logo.png ├── MockQueryable.Moq.csproj └── MoqExtensions.cs ├── MockQueryable.NSubstitute ├── Assets │ └── logo.png ├── MockQueryable.NSubstitute.csproj └── NSubstituteExtensions.cs ├── MockQueryable.Sample ├── MockQueryable.Sample.csproj ├── MyService.cs ├── MyServiceFakeItEasyTests.cs ├── MyServiceMoqTests.cs ├── MyServiceNSubstituteTests.cs ├── TestDbSetRepository.cs └── TestsSetup.cs └── MockQueryable.sln /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [romantitov] 4 | -------------------------------------------------------------------------------- /.github/workflows/dotnetcore.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Setup .NET Core 13 | uses: actions/setup-dotnet@v1 14 | with: 15 | dotnet-version: 3.1.100 16 | 17 | - name: Build with dotnet 18 | run: dotnet build src/MockQueryable/*.sln --configuration Release 19 | - name: Test with dotnet 20 | run: dotnet test src/MockQueryable/*.sln 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | # Build results (asp core 1.1) 27 | [Dd]ebug/netcoreapp1.1/ 28 | [Dd]ebugPublic/netcoreapp1.1/ 29 | [Rr]elease/netcoreapp1.1/ 30 | [Rr]eleases/netcoreapp1.1/ 31 | x64/netcoreapp1.1/ 32 | x86/netcoreapp1.1/ 33 | bld/netcoreapp1.1/ 34 | [Bb]in/netcoreapp1.1/ 35 | [Oo]bj/netcoreapp1.1/ 36 | [Ll]og/netcoreapp1.1/ 37 | 38 | # Visual Studio 2015 cache/options directory 39 | .vs/ 40 | # Uncomment if you have tasks that create the project's static files in wwwroot 41 | #wwwroot/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUNIT 48 | *.VisualState.xml 49 | TestResult.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # .NET Core 57 | project.lock.json 58 | project.fragment.lock.json 59 | artifacts/ 60 | **/Properties/launchSettings.json 61 | 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.pch 69 | *.pdb 70 | *.pgc 71 | *.pgd 72 | *.rsp 73 | *.sbr 74 | *.tlb 75 | *.tli 76 | *.tlh 77 | *.tmp 78 | *.tmp_proj 79 | *.log 80 | *.vspscc 81 | *.vssscc 82 | .builds 83 | *.pidb 84 | *.svclog 85 | *.scc 86 | 87 | # Chutzpah Test files 88 | _Chutzpah* 89 | 90 | # Visual C++ cache files 91 | ipch/ 92 | *.aps 93 | *.ncb 94 | *.opendb 95 | *.opensdf 96 | *.sdf 97 | *.cachefile 98 | *.VC.db 99 | *.VC.VC.opendb 100 | 101 | # Visual Studio profiler 102 | *.psess 103 | *.vsp 104 | *.vspx 105 | *.sap 106 | 107 | # TFS 2012 Local Workspace 108 | $tf/ 109 | 110 | # Guidance Automation Toolkit 111 | *.gpState 112 | 113 | # ReSharper is a .NET coding add-in 114 | _ReSharper*/ 115 | *.[Rr]e[Ss]harper 116 | *.DotSettings.user 117 | 118 | # JustCode is a .NET coding add-in 119 | .JustCode 120 | 121 | # TeamCity is a build add-in 122 | _TeamCity* 123 | 124 | # DotCover is a Code Coverage Tool 125 | *.dotCover 126 | 127 | # Visual Studio code coverage results 128 | *.coverage 129 | *.coveragexml 130 | 131 | # NCrunch 132 | _NCrunch_* 133 | .*crunch*.local.xml 134 | nCrunchTemp_* 135 | 136 | # MightyMoose 137 | *.mm.* 138 | AutoTest.Net/ 139 | 140 | # Web workbench (sass) 141 | .sass-cache/ 142 | 143 | # Installshield output folder 144 | [Ee]xpress/ 145 | 146 | # DocProject is a documentation generator add-in 147 | DocProject/buildhelp/ 148 | DocProject/Help/*.HxT 149 | DocProject/Help/*.HxC 150 | DocProject/Help/*.hhc 151 | DocProject/Help/*.hhk 152 | DocProject/Help/*.hhp 153 | DocProject/Help/Html2 154 | DocProject/Help/html 155 | 156 | # Click-Once directory 157 | publish/ 158 | 159 | # Publish Web Output 160 | *.[Pp]ublish.xml 161 | *.azurePubxml 162 | # TODO: Comment the next line if you want to checkin your web deploy settings 163 | # but database connection strings (with potential passwords) will be unencrypted 164 | *.pubxml 165 | *.publishproj 166 | 167 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 168 | # checkin your Azure Web App publish settings, but sensitive information contained 169 | # in these scripts will be unencrypted 170 | PublishScripts/ 171 | 172 | # NuGet Packages 173 | *.nupkg 174 | # The packages folder can be ignored because of Package Restore 175 | **/packages/* 176 | # except build/, which is used as an MSBuild target. 177 | !**/packages/build/ 178 | # Uncomment if necessary however generally it will be regenerated when needed 179 | #!**/packages/repositories.config 180 | # NuGet v3's project.json files produces more ignorable files 181 | *.nuget.props 182 | *.nuget.targets 183 | 184 | # Microsoft Azure Build Output 185 | csx/ 186 | *.build.csdef 187 | 188 | # Microsoft Azure Emulator 189 | ecf/ 190 | rcf/ 191 | 192 | # Windows Store app package directories and files 193 | AppPackages/ 194 | BundleArtifacts/ 195 | Package.StoreAssociation.xml 196 | _pkginfo.txt 197 | *.appx 198 | 199 | # Visual Studio cache files 200 | # files ending in .cache can be ignored 201 | *.[Cc]ache 202 | # but keep track of directories ending in .cache 203 | !*.[Cc]ache/ 204 | 205 | # Others 206 | ClientBin/ 207 | ~$* 208 | *~ 209 | *.dbmdl 210 | *.dbproj.schemaview 211 | *.jfm 212 | *.pfx 213 | *.publishsettings 214 | orleans.codegen.cs 215 | 216 | # Since there are multiple workflows, uncomment next line to ignore bower_components 217 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 218 | #bower_components/ 219 | 220 | # RIA/Silverlight projects 221 | Generated_Code/ 222 | 223 | # Backup & report files from converting an old project file 224 | # to a newer Visual Studio version. Backup files are not needed, 225 | # because we have git ;-) 226 | _UpgradeReport_Files/ 227 | Backup*/ 228 | UpgradeLog*.XML 229 | UpgradeLog*.htm 230 | 231 | # SQL Server files 232 | *.mdf 233 | *.ldf 234 | *.ndf 235 | 236 | # Business Intelligence projects 237 | *.rdl.data 238 | *.bim.layout 239 | *.bim_*.settings 240 | 241 | # Microsoft Fakes 242 | FakesAssemblies/ 243 | 244 | # GhostDoc plugin setting file 245 | *.GhostDoc.xml 246 | 247 | # Node.js Tools for Visual Studio 248 | .ntvs_analysis.dat 249 | node_modules/ 250 | 251 | # Typescript v1 declaration files 252 | typings/ 253 | 254 | # Visual Studio 6 build log 255 | *.plg 256 | 257 | # Visual Studio 6 workspace options file 258 | *.opt 259 | 260 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 261 | *.vbw 262 | 263 | # Visual Studio LightSwitch build output 264 | **/*.HTMLClient/GeneratedArtifacts 265 | **/*.DesktopClient/GeneratedArtifacts 266 | **/*.DesktopClient/ModelManifest.xml 267 | **/*.Server/GeneratedArtifacts 268 | **/*.Server/ModelManifest.xml 269 | _Pvt_Extensions 270 | 271 | # Paket dependency manager 272 | .paket/paket.exe 273 | paket-files/ 274 | 275 | # FAKE - F# Make 276 | .fake/ 277 | 278 | # JetBrains Rider 279 | .idea/ 280 | *.sln.iml 281 | 282 | # CodeRush 283 | .cr/ 284 | 285 | # Python Tools for Visual Studio (PTVS) 286 | __pycache__/ 287 | *.pyc 288 | 289 | # Cake - Uncomment if you are using it 290 | # tools/** 291 | # !tools/packages.config 292 | 293 | # Telerik's JustMock configuration file 294 | *.jmconfig 295 | 296 | # BizTalk build output 297 | *.btp.cs 298 | *.btm.cs 299 | *.odx.cs 300 | *.xsd.cs 301 | # ========================= 302 | # Windows detritus 303 | # ========================= 304 | 305 | # Windows image file caches 306 | Thumbs.db 307 | ehthumbs.db 308 | 309 | # Folder config file 310 | Desktop.ini 311 | 312 | # Recycle Bin used on file shares 313 | $RECYCLE.BIN/ 314 | 315 | # Mac desktop service store files 316 | .DS_Store 317 | 318 | # SASS Compiler cache 319 | .sass-cache 320 | 321 | # Visual Studio 2014 CTP 322 | **/*.sln.ide 323 | 324 | # Visual Studio temp something 325 | .vs/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | 3 | dotnet: 2.1 4 | 5 | dist: trusty 6 | 7 | solution: ./src/MockQueryable/MockQueryable.sln 8 | 9 | script: 10 | 11 | - cd src/MockQueryable 12 | 13 | - dotnet restore 14 | 15 | - dotnet build --configuration=Release 16 | 17 | - dotnet test ./MockQueryable.Sample/MockQueryable.Sample.csproj 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Raman Tsitou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # PR Details 2 | 3 | 4 | 5 | ## Description 6 | 7 | 8 | 9 | ## Related Issue 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## How Has This Been Tested 17 | 18 | 19 | 20 | 21 | ## Checklist 22 | 23 | 24 | 25 | 26 | - [ ] My code follows the code style of this project. 27 | - [ ] I have added tests to cover my changes. 28 | - [ ] All new and existing tests passed. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MockQueryable 3 | 4 | [![Build status](https://github.com/romantitov/MockQueryable/workflows/.NET%20Core/badge.svg)](https://github.com/romantitov/MockQueryable/actions) 5 | [![Build status](https://ci.appveyor.com/api/projects/status/ggdbipcyyfb4av9e?svg=true)](https://ci.appveyor.com/project/handybudget/mockqueryable) 6 | [![Build Status](https://travis-ci.org/romantitov/MockQueryable.svg?branch=master)](https://travis-ci.org/romantitov/MockQueryable) 7 | [![Downloads](https://img.shields.io/nuget/dt/MockQueryable.Moq.svg)](https://www.nuget.org/packages/MockQueryable.Moq/) 8 | [![Downloads](https://img.shields.io/nuget/dt/MockQueryable.NSubstitute.svg)](https://www.nuget.org/packages/MockQueryable.NSubstitute/) 9 | [![Downloads](https://img.shields.io/nuget/dt/MockQueryable.FakeItEasy.svg)](https://www.nuget.org/packages/MockQueryable.FakeItEasy/) 10 | 11 | 12 | [![Build history](https://buildstats.info/appveyor/chart/handybudget/mockqueryable)](https://ci.appveyor.com/project/handybudget/mockqueryable/history) 13 | 14 | 15 | 16 | Extensions for mocking [Entity Framework Core](https://github.com/aspnet/EntityFrameworkCore/) (EFCore) operations such ToListAsync, FirstOrDefaultAsync etc. by [Moq](https://github.com/moq/moq), [NSubstitute](http://nsubstitute.github.io/) or [FakeItEasy](https://fakeiteasy.github.io/) 17 | When writing tests for your application it is often desirable to avoid hitting the database. The extensions allow you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 18 | 19 | ### When should I use it? 20 | 21 | If you have something similar to the following code: 22 | ```csharp 23 | var query = _userRepository.GetQueryable(); 24 | 25 | await query.AnyAsync(x =>...) 26 | await query.FirstOrDefaultAsync(x =>...) 27 | query.CountAsync(x => ...) 28 | query.ToListAsync() 29 | //etc. 30 | ``` 31 | and you want to cover it by unit tests 32 | 33 | ### How do I get started? 34 | 35 | ```csharp 36 | //1 - create a List with test items 37 | var users = new List() 38 | { 39 | new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")}, 40 | ... 41 | }; 42 | 43 | //2 - build mock by extension 44 | var mock = users.AsQueryable().BuildMock(); 45 | 46 | //3 - setup the mock as Queryable for Moq 47 | _userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object); 48 | 49 | //3 - setup the mock as Queryable for NSubstitute 50 | _userRepository.GetQueryable().Returns(mock); 51 | 52 | //3 - setup the mock as Queryable for FakeItEasy 53 | A.CallTo(() => userRepository.GetQueryable()).Returns(mock); 54 | ``` 55 | 56 | Do you prefer *DbSet*? 57 | 58 | ```csharp 59 | //2 - build mock by extension 60 | var mock = users.AsQueryable().BuildMockDbSet(); 61 | 62 | //3 - setup DbSet for Moq 63 | var userRepository = new TestDbSetRepository(mock.Object); 64 | 65 | //3 - setup DbSet for NSubstitute or FakeItEasy 66 | var userRepository = new TestDbSetRepository(mock); 67 | ``` 68 | 69 | Do you use *DbQuery*? 70 | 71 | ```csharp 72 | //2 - build mock by extension 73 | var mock = users.AsQueryable().BuildMockDbQuery(); 74 | 75 | //3 - setup the mock as Queryable for Moq 76 | _userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object); 77 | 78 | //3 - setup the mock as Queryable for NSubstitute 79 | _userRepository.GetQueryable().Returns(mock); 80 | 81 | //3 - setup the mock as Queryable for FakeItEasy 82 | A.CallTo(() => userRepository.GetQueryable()).Returns(mock); 83 | ``` 84 | 85 | Check out the [sample project](https://github.com/romantitov/MockQueryable/tree/master/src/MockQueryable/MockQueryable.Sample) 86 | 87 | ### Where can I get it? 88 | 89 | First, [install NuGet](http://docs.nuget.org/docs/start-here/installing-nuget). 90 | 91 | If you are using **Moq** - then, install [MockQueryable.Moq](https://www.nuget.org/packages/MockQueryable.Moq/) from the package manager console: 92 | 93 | ``` 94 | PM> Install-Package MockQueryable.Moq 95 | ``` 96 | 97 | If you are using **NSubstitute** - then, install [MockQueryable.NSubstitute](https://www.nuget.org/packages/MockQueryable.NSubstitute/) from the package manager console: 98 | 99 | ``` 100 | PM> Install-Package MockQueryable.NSubstitute 101 | ``` 102 | 103 | If you are using **FakeItEasy** - then, install [MockQueryable.FakeItEasy](https://www.nuget.org/packages/MockQueryable.FakeItEasy/) from the package manager console: 104 | 105 | ``` 106 | PM> Install-Package MockQueryable.FakeItEasy 107 | ``` 108 | 109 | ### Can I use it with my favorite mock framework? 110 | 111 | You can install [MockQueryable.EntityFrameworkCore](https://www.nuget.org/packages/MockQueryable.EntityFrameworkCore/) from the package manager console: 112 | 113 | ``` 114 | PM> Install-Package MockQueryable.EntityFrameworkCore 115 | ``` 116 | [![Downloads](https://img.shields.io/nuget/dt/MockQueryable.EntityFrameworkCore.svg)](https://www.nuget.org/packages/MockQueryable.EntityFrameworkCore/) 117 | 118 | or even [MockQueryable.Core](https://www.nuget.org/packages/MockQueryable.Core/) 119 | ``` 120 | PM> Install-Package MockQueryable.Core 121 | ``` 122 | [![Downloads](https://img.shields.io/nuget/dt/MockQueryable.Core.svg)](https://www.nuget.org/packages/MockQueryable.Core/) 123 | 124 | 125 | Then [make own extension](https://github.com/romantitov/MockQueryable/blob/master/src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs) for your favorite mock framework 126 | -------------------------------------------------------------------------------- /src/MockQueryable/Assets/logo-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/Assets/logo-github.png -------------------------------------------------------------------------------- /src/MockQueryable/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Core/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/MockQueryable.Core/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | MockQueryable.Core 6 | Roman Titov 7 | 8 | Core package for MockQueryable extensions for mocking operations such ToListAsync, FirstOrDefaultAsync etc. 9 | When writing tests for your application it is often desirable to avoid hitting the database. The extension allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 10 | 11 | true 12 | https://github.com/romantitov/MockQueryable 13 | https://github.com/romantitov/MockQueryable 14 | Mock EntityFrameworkCore Queryable mock EF UnitTests EntityFrameworkCore 15 | true 16 | Added support .Net 5.0 17 | 5.0.0 18 | 5.0.0.0 19 | 5.0.0.0 20 | 21 | LICENSE 22 | logo.png 23 | 24 | 25 | 26 | 27 | True 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | True 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Core/TestExpressionVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace MockQueryable.Core 4 | { 5 | public class TestExpressionVisitor : ExpressionVisitor 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | 7 | namespace MockQueryable.Core 8 | { 9 | public abstract class TestQueryProvider : IOrderedQueryable, IQueryProvider 10 | { 11 | private IEnumerable _enumerable; 12 | 13 | protected TestQueryProvider(Expression expression) 14 | { 15 | Expression = expression; 16 | } 17 | 18 | protected TestQueryProvider(IEnumerable enumerable) 19 | { 20 | _enumerable = enumerable; 21 | Expression = enumerable.AsQueryable().Expression; 22 | } 23 | 24 | public IQueryable CreateQuery(Expression expression) 25 | { 26 | if (expression is MethodCallExpression m) 27 | { 28 | var resultType = m.Method.ReturnType; // it should be IQueryable 29 | var tElement = resultType.GetGenericArguments().First(); 30 | return (IQueryable) CreateInstance(tElement, expression); 31 | } 32 | 33 | return CreateQuery(expression); 34 | } 35 | 36 | public IQueryable CreateQuery(Expression expression) 37 | { 38 | return (IQueryable) CreateInstance(typeof(TEntity), expression); 39 | } 40 | 41 | private object CreateInstance(Type tElement, Expression expression) 42 | { 43 | var queryType = GetType().GetGenericTypeDefinition().MakeGenericType(tElement); 44 | return Activator.CreateInstance(queryType, expression); 45 | } 46 | 47 | public object Execute(Expression expression) 48 | { 49 | return CompileExpressionItem(expression); 50 | } 51 | 52 | public TResult Execute(Expression expression) 53 | { 54 | return CompileExpressionItem(expression); 55 | } 56 | 57 | IEnumerator IEnumerable.GetEnumerator() 58 | { 59 | if (_enumerable == null) _enumerable = CompileExpressionItem>(Expression); 60 | return _enumerable.GetEnumerator(); 61 | } 62 | 63 | IEnumerator IEnumerable.GetEnumerator() 64 | { 65 | if (_enumerable == null) _enumerable = CompileExpressionItem>(Expression); 66 | return _enumerable.GetEnumerator(); 67 | } 68 | 69 | public Type ElementType => typeof(T); 70 | 71 | public Expression Expression { get; } 72 | 73 | public IQueryProvider Provider => this; 74 | 75 | private static TResult CompileExpressionItem(Expression expression) 76 | { 77 | var visitor = new TestExpressionVisitor(); 78 | var body = visitor.Visit(expression); 79 | var f = Expression.Lambda>(body ?? throw new InvalidOperationException($"{nameof(body)} is null"), (IEnumerable) null); 80 | return f.Compile()(); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.EntityFrameworkCore/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/MockQueryable.EntityFrameworkCore/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryable.EntityFrameworkCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | MockQueryable.EntityFrameworkCore 6 | Roman Titov 7 | 8 | Extension for mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc. 9 | When writing tests for your application it is often desirable to avoid hitting the database. The extension allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 10 | 11 | true 12 | true 13 | https://github.com/romantitov/MockQueryable 14 | https://github.com/romantitov/MockQueryable 15 | Mock EntityFrameworkCore Queryable mock EF UnitTests EntityFrameworkCore 16 | true 17 | Added support .Net 5.0 18 | 5.0.0 19 | 5.0.0.0 20 | 5.0.0.0 21 | 22 | LICENSE 23 | logo.png 24 | 25 | 26 | 27 | 28 | True 29 | 30 | 31 | 32 | 33 | 34 | True 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.EntityFrameworkCore/TestAsyncEnumerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace MockQueryable.EntityFrameworkCore 6 | { 7 | public class TestAsyncEnumerator : IAsyncEnumerator 8 | { 9 | private readonly IEnumerator _enumerator; 10 | 11 | public TestAsyncEnumerator(IEnumerator enumerator) 12 | { 13 | _enumerator = enumerator ?? throw new ArgumentNullException(); 14 | } 15 | 16 | public T Current => _enumerator.Current; 17 | 18 | public ValueTask DisposeAsync() 19 | { 20 | _enumerator.Dispose(); 21 | return new ValueTask(); 22 | } 23 | 24 | public ValueTask MoveNextAsync() 25 | { 26 | return new ValueTask(_enumerator.MoveNext()); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.EntityFrameworkCore.Query; 8 | using MockQueryable.Core; 9 | 10 | namespace MockQueryable.EntityFrameworkCore 11 | { 12 | public class TestAsyncEnumerableEfCore: TestQueryProvider, IAsyncEnumerable, IAsyncQueryProvider 13 | { 14 | public TestAsyncEnumerableEfCore(Expression expression) : base(expression) 15 | { 16 | } 17 | 18 | public TestAsyncEnumerableEfCore(IEnumerable enumerable) : base(enumerable) 19 | { 20 | } 21 | 22 | public TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken) 23 | { 24 | var expectedResultType = typeof(TResult).GetGenericArguments()[0]; 25 | var executionResult = typeof(IQueryProvider) 26 | .GetMethods() 27 | .First(method => method.Name == nameof(IQueryProvider.Execute) && method.IsGenericMethod) 28 | .MakeGenericMethod(expectedResultType) 29 | .Invoke(this, new object[] { expression }); 30 | 31 | return (TResult)typeof(Task).GetMethod(nameof(Task.FromResult)) 32 | .MakeGenericMethod(expectedResultType) 33 | .Invoke(null, new[] { executionResult }); 34 | } 35 | 36 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) 37 | { 38 | return new TestAsyncEnumerator(this.AsEnumerable().GetEnumerator()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.FakeItEasy/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/MockQueryable.FakeItEasy/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using FakeItEasy; 6 | using Microsoft.EntityFrameworkCore; 7 | using MockQueryable.EntityFrameworkCore; 8 | 9 | namespace MockQueryable.FakeItEasy 10 | { 11 | public static class FakeItEasyExtensions 12 | { 13 | public static IQueryable BuildMock(this IQueryable data) where TEntity : class 14 | { 15 | var mock = A.Fake>( 16 | d => d.Implements>().Implements>()); 17 | var enumerable = new TestAsyncEnumerableEfCore(data); 18 | ((IAsyncEnumerable) mock).ConfigureAsyncEnumerableCalls(enumerable); 19 | mock.ConfigureQueryableCalls(enumerable, data); 20 | 21 | return mock; 22 | } 23 | 24 | public static DbSet BuildMockDbSet(this IQueryable data) where TEntity : class 25 | { 26 | var mock = A.Fake>( 27 | d => d.Implements>().Implements>()); 28 | var enumerable = new TestAsyncEnumerableEfCore(data); 29 | mock.ConfigureQueryableCalls(enumerable, data); 30 | mock.ConfigureAsyncEnumerableCalls(enumerable); 31 | return mock; 32 | } 33 | 34 | 35 | private static void ConfigureQueryableCalls( 36 | this IQueryable mock, 37 | IQueryProvider queryProvider, 38 | IQueryable data) where TEntity : class 39 | { 40 | A.CallTo(() => mock.Provider).Returns(queryProvider); 41 | A.CallTo(() => mock.Expression).Returns(data?.Expression); 42 | A.CallTo(() => mock.ElementType).Returns(data?.ElementType); 43 | A.CallTo(() => mock.GetEnumerator()).ReturnsLazily(() => data?.GetEnumerator()); 44 | } 45 | 46 | private static void ConfigureAsyncEnumerableCalls( 47 | this IAsyncEnumerable mock, 48 | IAsyncEnumerable enumerable) 49 | { 50 | A.CallTo(() => mock.GetAsyncEnumerator(A.Ignored)) 51 | .Returns(enumerable.GetAsyncEnumerator()); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.FakeItEasy/MockQueryable.FakeItEasy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | MockQueryable.FakeItEasy 6 | Roman Titov 7 | 8 | Extension for mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc. 9 | When writing tests for your application it is often desirable to avoid hitting the database. The extension allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 10 | 11 | true 12 | https://github.com/romantitov/MockQueryable 13 | https://github.com/romantitov/MockQueryable 14 | Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests FakeItEasy 15 | true 16 | Added support .Net 5.0 17 | 5.0.0 18 | 5.0.0.0 19 | 5.0.0.0 20 | 21 | LICENSE 22 | logo.png 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | True 32 | 33 | 34 | 35 | 36 | 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Moq/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/MockQueryable.Moq/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Moq/MockQueryable.Moq.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | MockQueryable.Moq 6 | Roman Titov 7 | 8 | Extension for mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc. 9 | When writing tests for your application it is often desirable to avoid hitting the database. The extension allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 10 | 11 | true 12 | https://github.com/romantitov/MockQueryable 13 | https://github.com/romantitov/MockQueryable 14 | Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests EntityFrameworkCore Moq 15 | true 16 | Added support .Net 5.0 17 | 5.0.0 18 | 5.0.0.0 19 | 5.0.0.0 20 | 21 | LICENSE 22 | logo.png 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | True 33 | 34 | 35 | 36 | 37 | 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using Microsoft.EntityFrameworkCore; 6 | using MockQueryable.EntityFrameworkCore; 7 | using Moq; 8 | 9 | namespace MockQueryable.Moq 10 | { 11 | public static class MoqExtensions 12 | { 13 | public static Mock> BuildMock(this IQueryable data) where TEntity : class 14 | { 15 | var mock = new Mock>(); 16 | var enumerable = new TestAsyncEnumerableEfCore(data); 17 | mock.As>().ConfigureAsyncEnumerableCalls(enumerable); 18 | mock.ConfigureQueryableCalls(enumerable, data); 19 | return mock; 20 | } 21 | 22 | public static Mock> BuildMockDbSet(this IQueryable data) where TEntity : class 23 | { 24 | var mock = new Mock>(); 25 | var enumerable = new TestAsyncEnumerableEfCore(data); 26 | mock.As>().ConfigureAsyncEnumerableCalls(enumerable); 27 | mock.As>().ConfigureQueryableCalls(enumerable, data); 28 | mock.ConfigureDbSetCalls(); 29 | return mock; 30 | } 31 | 32 | private static void ConfigureDbSetCalls(this Mock> mock) 33 | where TEntity : class 34 | { 35 | mock.Setup(m => m.AsQueryable()).Returns(mock.Object); 36 | mock.Setup(m => m.AsAsyncEnumerable()).Returns(mock.Object); 37 | } 38 | 39 | private static void ConfigureQueryableCalls( 40 | this Mock> mock, 41 | IQueryProvider queryProvider, 42 | IQueryable data) where TEntity : class 43 | { 44 | mock.Setup(m => m.Provider).Returns(queryProvider); 45 | mock.Setup(m => m.Expression).Returns(data?.Expression); 46 | mock.Setup(m => m.ElementType).Returns(data?.ElementType); 47 | mock.Setup(m => m.GetEnumerator()).Returns(() => data?.GetEnumerator()); 48 | } 49 | 50 | private static void ConfigureAsyncEnumerableCalls( 51 | this Mock> mock, 52 | IAsyncEnumerable enumerable) 53 | { 54 | mock.Setup(d => d.GetAsyncEnumerator(It.IsAny())) 55 | .Returns(() => enumerable.GetAsyncEnumerator()); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.NSubstitute/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/MockQueryable/874aa934c84336440a8773eec28f6af77db036ca/src/MockQueryable/MockQueryable.NSubstitute/Assets/logo.png -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.NSubstitute/MockQueryable.NSubstitute.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | MockQueryable.NSubstitute 6 | Roman Titov 7 | 8 | Extension for mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc. 9 | When writing tests for your application it is often desirable to avoid hitting the database. The extension allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data. 10 | 11 | true 12 | https://github.com/romantitov/MockQueryable 13 | https://github.com/romantitov/MockQueryable 14 | Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests EntityFrameworkCore NSubstitute 15 | true 16 | Added support .Net 5.0 17 | 5.0.0 18 | 5.0.0.0 19 | 5.0.0.0 20 | 21 | LICENSE 22 | logo.png 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | True 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using Microsoft.EntityFrameworkCore; 6 | using MockQueryable.EntityFrameworkCore; 7 | using NSubstitute; 8 | 9 | namespace MockQueryable.NSubstitute 10 | { 11 | public static class NSubstituteExtensions 12 | { 13 | public static IQueryable BuildMock(this IQueryable data) where TEntity : class 14 | { 15 | var mock = Substitute.For, IAsyncEnumerable>(); 16 | var enumerable = new TestAsyncEnumerableEfCore(data); 17 | ((IAsyncEnumerable) mock).ConfigureAsyncEnumerableCalls(enumerable); 18 | mock.ConfigureQueryableCalls(enumerable, data); 19 | return mock; 20 | } 21 | 22 | public static DbSet BuildMockDbSet(this IQueryable data) where TEntity : class 23 | { 24 | var mock = Substitute.For, IQueryable, IAsyncEnumerable>(); 25 | var enumerable = new TestAsyncEnumerableEfCore(data); 26 | mock.ConfigureAsyncEnumerableCalls(enumerable); 27 | mock.ConfigureQueryableCalls(enumerable, data); 28 | return mock; 29 | } 30 | 31 | 32 | private static void ConfigureQueryableCalls( 33 | this IQueryable mock, 34 | IQueryProvider queryProvider, 35 | IQueryable data) where TEntity : class 36 | { 37 | mock.Provider.Returns(queryProvider); 38 | mock.Expression.Returns(data?.Expression); 39 | mock.ElementType.Returns(data?.ElementType); 40 | mock.GetEnumerator().Returns(info => data?.GetEnumerator()); 41 | } 42 | 43 | private static void ConfigureAsyncEnumerableCalls( 44 | this IAsyncEnumerable mock, 45 | IAsyncEnumerable enumerable) 46 | { 47 | mock.GetAsyncEnumerator(Arg.Any()).Returns(args => enumerable.GetAsyncEnumerator()); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/MyService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using AutoMapper; 6 | using AutoMapper.QueryableExtensions; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace MockQueryable.Sample 10 | { 11 | public class MyService 12 | { 13 | private readonly IUserRepository _userRepository; 14 | 15 | public static void Initialize() 16 | { 17 | Mapper.Initialize(cfg => cfg.CreateMap() 18 | .ForMember(dto => dto.FirstName, conf => conf.MapFrom(ol => ol.FirstName)) 19 | .ForMember(dto => dto.LastName, conf => conf.MapFrom(ol => ol.LastName))); 20 | Mapper.Configuration.AssertConfigurationIsValid(); 21 | } 22 | 23 | public MyService(IUserRepository userRepository) 24 | { 25 | this._userRepository = userRepository; 26 | } 27 | 28 | public async Task CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth) 29 | { 30 | var query = _userRepository.GetQueryable(); 31 | 32 | if (await query.AnyAsync(x => x.LastName == lastName && x.DateOfBirth==dateOfBirth)) 33 | { 34 | throw new ApplicationException("User already exist"); 35 | } 36 | 37 | var existUser = await query.FirstOrDefaultAsync(x => x.FirstName == firstName); 38 | if (existUser != null) 39 | { 40 | throw new ApplicationException("User with FirstName already exist"); 41 | } 42 | 43 | if (await query.CountAsync(x => x.DateOfBirth == dateOfBirth.Date) > 3) 44 | { 45 | throw new ApplicationException("Users with DateOfBirth more than limit"); 46 | } 47 | 48 | await _userRepository.CreateUser(new UserEntity 49 | { 50 | FirstName = firstName, 51 | LastName = lastName, 52 | DateOfBirth = dateOfBirth.Date, 53 | }); 54 | 55 | } 56 | 57 | public async Task> GetUserReports(DateTime dateFrom, DateTime dateTo) 58 | { 59 | var query = _userRepository.GetQueryable(); 60 | 61 | query = query.Where(x => x.DateOfBirth >= dateFrom.Date); 62 | query = query.Where(x => x.DateOfBirth <= dateTo.Date); 63 | 64 | return await query.Select(x => new UserReport 65 | { 66 | FirstName = x.FirstName, 67 | LastName = x.LastName, 68 | }).ToListAsync(); 69 | } 70 | 71 | 72 | public async Task> GetUserReportsAutoMap(DateTime dateFrom, DateTime dateTo) 73 | { 74 | var query = _userRepository.GetQueryable(); 75 | 76 | query = query.Where(x => x.DateOfBirth >= dateFrom.Date); 77 | query = query.Where(x => x.DateOfBirth <= dateTo.Date); 78 | 79 | return await query.ProjectTo().ToListAsync(); 80 | } 81 | } 82 | 83 | public interface IUserRepository 84 | { 85 | IQueryable GetQueryable(); 86 | 87 | Task CreateUser(UserEntity user); 88 | 89 | List GetAll(); 90 | } 91 | 92 | 93 | public class UserReport 94 | { 95 | public string FirstName { get; set; } 96 | public string LastName { get; set; } 97 | } 98 | 99 | public class UserEntity 100 | { 101 | public Guid Id { get; set; } 102 | public string FirstName { get; set; } 103 | public string LastName { get; set; } 104 | public DateTime DateOfBirth { get; set; } 105 | } 106 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/MyServiceFakeItEasyTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using FakeItEasy; 8 | using MockQueryable.FakeItEasy; 9 | using NUnit.Framework; 10 | 11 | namespace MockQueryable.Sample 12 | { 13 | [TestFixture] 14 | public class MyServiceFakeItEasyTests 15 | { 16 | private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); 17 | 18 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 19 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 20 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 21 | public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 22 | { 23 | //arrange 24 | 25 | var userRepository = A.Fake(); 26 | var service = new MyService(userRepository); 27 | var users = new List 28 | { 29 | new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 30 | new UserEntity{FirstName = "ExistFirstName"}, 31 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 32 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 33 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 34 | }; 35 | //expect 36 | var mock = users.AsQueryable().BuildMock(); 37 | A.CallTo(() => userRepository.GetQueryable()).Returns(mock); 38 | //act 39 | var ex = Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 40 | //assert 41 | Assert.AreEqual(expectedError, ex.Message); 42 | 43 | } 44 | 45 | [TestCase("01/20/2012", "06/20/2018", 5)] 46 | [TestCase("01/20/2012", "06/20/2012", 4)] 47 | [TestCase("01/20/2012", "02/20/2012", 3)] 48 | [TestCase("01/20/2010", "02/20/2011", 0)] 49 | public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) 50 | { 51 | //arrange 52 | var userRepository = A.Fake(); 53 | var service = new MyService(userRepository); 54 | var users = new List 55 | { 56 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 57 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 58 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 59 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 60 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 61 | }; 62 | //expect 63 | var mock = users.AsQueryable().BuildMock(); 64 | A.CallTo(() => userRepository.GetQueryable()).Returns(mock); 65 | //act 66 | var result = await service.GetUserReports(from, to); 67 | //assert 68 | Assert.AreEqual(expectedCount, result.Count); 69 | 70 | } 71 | 72 | 73 | [TestCase("01/20/2012", "06/20/2018", 5)] 74 | [TestCase("01/20/2012", "06/20/2012", 4)] 75 | [TestCase("01/20/2012", "02/20/2012", 3)] 76 | [TestCase("01/20/2010", "02/20/2011", 0)] 77 | public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) 78 | { 79 | //arrange 80 | var userRepository = A.Fake(); 81 | var service = new MyService(userRepository); 82 | var users = new List 83 | { 84 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 85 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 86 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 87 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 88 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 89 | }; 90 | //expect 91 | var mock = users.AsQueryable().BuildMock(); 92 | A.CallTo(() => userRepository.GetQueryable()).Returns(mock); 93 | //act 94 | var result = await service.GetUserReportsAutoMap(from, to); 95 | //assert 96 | Assert.AreEqual(expectedCount, result.Count); 97 | 98 | } 99 | 100 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 101 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 102 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 103 | public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 104 | { 105 | //arrange 106 | var users = new List 107 | { 108 | new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 109 | new UserEntity{FirstName = "ExistFirstName"}, 110 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 111 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 112 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 113 | }; 114 | var mock = users.AsQueryable().BuildMockDbSet(); 115 | var userRepository = new TestDbSetRepository(mock); 116 | var service = new MyService(userRepository); 117 | //act 118 | var ex = Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 119 | //assert 120 | Assert.AreEqual(expectedError, ex.Message); 121 | 122 | } 123 | 124 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] 125 | public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) 126 | { 127 | //arrange 128 | var userEntities = new List(); 129 | var mock = userEntities.AsQueryable().BuildMockDbSet(); 130 | A.CallTo(() => mock.AddAsync(A._, A._)) 131 | .ReturnsLazily(call => 132 | { 133 | userEntities.Add((UserEntity) call.Arguments[0]); 134 | return default; 135 | }); 136 | var userRepository = new TestDbSetRepository(mock); 137 | var service = new MyService(userRepository); 138 | //act 139 | await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); 140 | // assert 141 | var entity = mock.Single(); 142 | Assert.AreEqual(firstName, entity.FirstName); 143 | Assert.AreEqual(lastName, entity.LastName); 144 | Assert.AreEqual(dateOfBirth, entity.DateOfBirth); 145 | } 146 | 147 | [TestCase("01/20/2012", "06/20/2018", 5)] 148 | [TestCase("01/20/2012", "06/20/2012", 4)] 149 | [TestCase("01/20/2012", "02/20/2012", 3)] 150 | [TestCase("01/20/2010", "02/20/2011", 0)] 151 | public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) 152 | { 153 | //arrange 154 | var users = new List 155 | { 156 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 157 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 158 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 159 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 160 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 161 | }; 162 | var mock = users.AsQueryable().BuildMockDbSet(); 163 | var userRepository = new TestDbSetRepository(mock); 164 | var service = new MyService(userRepository); 165 | //act 166 | var result = await service.GetUserReports(from, to); 167 | //assert 168 | Assert.AreEqual(expectedCount, result.Count); 169 | } 170 | 171 | 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/MyServiceMoqTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.EntityFrameworkCore; 8 | using MockQueryable.Moq; 9 | using Moq; 10 | using NUnit.Framework; 11 | 12 | namespace MockQueryable.Sample 13 | { 14 | [TestFixture] 15 | public class MyServiceMoqTests 16 | { 17 | private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); 18 | 19 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 20 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 21 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 22 | public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 23 | { 24 | //arrange 25 | var userRepository = new Mock(); 26 | var service = new MyService(userRepository.Object); 27 | var users = new List 28 | { 29 | new UserEntity 30 | {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 31 | new UserEntity {FirstName = "ExistFirstName"}, 32 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 33 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 34 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)} 35 | }; 36 | //expect 37 | var mock = users.AsQueryable().BuildMock(); 38 | userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object); 39 | //act 40 | var ex = Assert.ThrowsAsync(() => 41 | service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 42 | //assert 43 | Assert.AreEqual(expectedError, ex.Message); 44 | } 45 | 46 | [TestCase("01/20/2012", "06/20/2018", 5)] 47 | [TestCase("01/20/2012", "06/20/2012", 4)] 48 | [TestCase("01/20/2012", "02/20/2012", 3)] 49 | [TestCase("01/20/2010", "02/20/2011", 0)] 50 | public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) 51 | { 52 | //arrange 53 | var userRepository = new Mock(); 54 | var service = new MyService(userRepository.Object); 55 | var users = new List 56 | { 57 | new UserEntity 58 | { 59 | FirstName = "FirstName1", LastName = "LastName", 60 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 61 | }, 62 | new UserEntity 63 | { 64 | FirstName = "FirstName2", LastName = "LastName", 65 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 66 | }, 67 | new UserEntity 68 | { 69 | FirstName = "FirstName3", LastName = "LastName", 70 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 71 | }, 72 | new UserEntity 73 | { 74 | FirstName = "FirstName3", LastName = "LastName", 75 | DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) 76 | }, 77 | new UserEntity 78 | { 79 | FirstName = "FirstName5", LastName = "LastName", 80 | DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) 81 | } 82 | }; 83 | //expect 84 | var mock = users.AsQueryable().BuildMock(); 85 | userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object); 86 | //act 87 | var result = await service.GetUserReports(from, to); 88 | //assert 89 | Assert.AreEqual(expectedCount, result.Count); 90 | } 91 | 92 | 93 | 94 | [TestCase("01/20/2012", "06/20/2018", 5)] 95 | [TestCase("01/20/2012", "06/20/2012", 4)] 96 | [TestCase("01/20/2012", "02/20/2012", 3)] 97 | [TestCase("01/20/2010", "02/20/2011", 0)] 98 | public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) 99 | { 100 | //arrange 101 | var userRepository = new Mock(); 102 | var service = new MyService(userRepository.Object); 103 | var users = new List 104 | { 105 | new UserEntity 106 | { 107 | FirstName = "FirstName1", LastName = "LastName", 108 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 109 | }, 110 | new UserEntity 111 | { 112 | FirstName = "FirstName2", LastName = "LastName", 113 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 114 | }, 115 | new UserEntity 116 | { 117 | FirstName = "FirstName3", LastName = "LastName", 118 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 119 | }, 120 | new UserEntity 121 | { 122 | FirstName = "FirstName3", LastName = "LastName", 123 | DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) 124 | }, 125 | new UserEntity 126 | { 127 | FirstName = "FirstName5", LastName = "LastName", 128 | DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) 129 | } 130 | }; 131 | //expect 132 | var mock = users.AsQueryable().BuildMock(); 133 | userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object); 134 | //act 135 | var result = await service.GetUserReportsAutoMap(from, to); 136 | //assert 137 | Assert.AreEqual(expectedCount, result.Count); 138 | } 139 | 140 | 141 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 142 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 143 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 144 | public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 145 | { 146 | //arrange 147 | var users = new List 148 | { 149 | new UserEntity 150 | {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 151 | new UserEntity {FirstName = "ExistFirstName"}, 152 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 153 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, 154 | new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)} 155 | }; 156 | var mock = users.AsQueryable().BuildMockDbSet(); 157 | var userRepository = new TestDbSetRepository(mock.Object); 158 | var service = new MyService(userRepository); 159 | //act 160 | var ex = Assert.ThrowsAsync(() => 161 | service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 162 | //assert 163 | Assert.AreEqual(expectedError, ex.Message); 164 | } 165 | 166 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] 167 | public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) 168 | { 169 | //arrange 170 | var userEntities = new List(); 171 | var mock = userEntities.AsQueryable().BuildMockDbSet(); 172 | mock.Setup(set => set.AddAsync(It.IsAny(), It.IsAny())) 173 | .Callback((UserEntity entity, CancellationToken _) => userEntities.Add(entity)); 174 | var userRepository = new TestDbSetRepository(mock.Object); 175 | var service = new MyService(userRepository); 176 | //act 177 | await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); 178 | // assert 179 | var entity = mock.Object.Single(); 180 | Assert.AreEqual(firstName, entity.FirstName); 181 | Assert.AreEqual(lastName, entity.LastName); 182 | Assert.AreEqual(dateOfBirth, entity.DateOfBirth); 183 | } 184 | 185 | [TestCase("01/20/2012", "06/20/2018", 5)] 186 | [TestCase("01/20/2012", "06/20/2012", 4)] 187 | [TestCase("01/20/2012", "02/20/2012", 3)] 188 | [TestCase("01/20/2010", "02/20/2011", 0)] 189 | public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) 190 | { 191 | //arrange 192 | var users = new List 193 | { 194 | new UserEntity 195 | { 196 | FirstName = "FirstName1", LastName = "LastName", 197 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 198 | }, 199 | new UserEntity 200 | { 201 | FirstName = "FirstName2", LastName = "LastName", 202 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 203 | }, 204 | new UserEntity 205 | { 206 | FirstName = "FirstName3", LastName = "LastName", 207 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 208 | }, 209 | new UserEntity 210 | { 211 | FirstName = "FirstName3", LastName = "LastName", 212 | DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) 213 | }, 214 | new UserEntity 215 | { 216 | FirstName = "FirstName5", LastName = "LastName", 217 | DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) 218 | } 219 | }; 220 | var mock = users.AsQueryable().BuildMockDbSet(); 221 | var userRepository = new TestDbSetRepository(mock.Object); 222 | var service = new MyService(userRepository); 223 | //act 224 | var result = await service.GetUserReports(from, to); 225 | //assert 226 | Assert.AreEqual(expectedCount, result.Count); 227 | } 228 | 229 | [TestCase] 230 | public void DbSetGetAllUserEntity() 231 | { 232 | //arrange 233 | var users = new List 234 | { 235 | new UserEntity 236 | { 237 | FirstName = "FirstName1", LastName = "LastName", 238 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 239 | }, 240 | new UserEntity 241 | { 242 | FirstName = "FirstName2", LastName = "LastName", 243 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 244 | }, 245 | new UserEntity 246 | { 247 | FirstName = "FirstName3", LastName = "LastName", 248 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 249 | }, 250 | new UserEntity 251 | { 252 | FirstName = "FirstName3", LastName = "LastName", 253 | DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) 254 | }, 255 | new UserEntity 256 | { 257 | FirstName = "FirstName5", LastName = "LastName", 258 | DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) 259 | } 260 | }; 261 | var mock = users.AsQueryable().BuildMockDbSet(); 262 | var userRepository = new TestDbSetRepository(mock.Object); 263 | //act 264 | var result = userRepository.GetAll(); 265 | //assert 266 | Assert.AreEqual(users.Count, result.Count); 267 | } 268 | 269 | [TestCase] 270 | public async Task DbSetFindAsyncUserEntity() 271 | { 272 | //arrange 273 | var userId = Guid.NewGuid(); 274 | var users = new List 275 | { 276 | new UserEntity 277 | { 278 | Id = Guid.NewGuid(), 279 | FirstName = "FirstName1", LastName = "LastName", 280 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 281 | }, 282 | new UserEntity 283 | { 284 | Id = Guid.NewGuid(), 285 | FirstName = "FirstName2", LastName = "LastName", 286 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 287 | }, 288 | new UserEntity 289 | { 290 | Id = userId, 291 | FirstName = "FirstName3", LastName = "LastName", 292 | DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) 293 | }, 294 | new UserEntity 295 | { 296 | Id = Guid.NewGuid(), 297 | FirstName = "FirstName3", LastName = "LastName", 298 | DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) 299 | }, 300 | new UserEntity 301 | { 302 | Id = Guid.NewGuid(), 303 | FirstName = "FirstName5", LastName = "LastName", 304 | DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) 305 | } 306 | }; 307 | 308 | var mock = users.AsQueryable().BuildMockDbSet(); 309 | mock.Setup(x => x.FindAsync(It.IsAny())).ReturnsAsync((object[] ids) => 310 | { 311 | var id = (Guid) ids.First(); 312 | return users.FirstOrDefault(x => x.Id == id); 313 | }); 314 | var userRepository = new TestDbSetRepository(mock.Object); 315 | 316 | //act 317 | var result = await ((DbSet)userRepository.GetQueryable()).FindAsync(userId); 318 | 319 | //assert 320 | Assert.IsNotNull(result); 321 | Assert.AreEqual("FirstName3", result.FirstName); 322 | } 323 | } 324 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/MyServiceNSubstituteTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using MockQueryable.NSubstitute; 7 | using NSubstitute; 8 | using NUnit.Framework; 9 | 10 | namespace MockQueryable.Sample 11 | { 12 | [TestFixture] 13 | public class MyServiceNSubstituteTests 14 | { 15 | private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); 16 | 17 | 18 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 19 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 20 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 21 | public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 22 | { 23 | //arrange 24 | var userRepository = Substitute.For(); 25 | var service = new MyService(userRepository); 26 | var users = new List 27 | { 28 | new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 29 | new UserEntity{FirstName = "ExistFirstName"}, 30 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 31 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 32 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 33 | }; 34 | //expect 35 | var mock = users.AsQueryable().BuildMock(); 36 | userRepository.GetQueryable().Returns(mock); 37 | //act 38 | var ex= Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 39 | //assert 40 | Assert.AreEqual(expectedError, ex.Message); 41 | 42 | } 43 | 44 | [TestCase("01/20/2012", "06/20/2018",5)] 45 | [TestCase("01/20/2012", "06/20/2012",4)] 46 | [TestCase("01/20/2012", "02/20/2012",3)] 47 | [TestCase("01/20/2010", "02/20/2011",0)] 48 | public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) 49 | { 50 | //arrange 51 | var userRepository = Substitute.For(); 52 | var service = new MyService(userRepository); 53 | var users = new List 54 | { 55 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 56 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 57 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 58 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 59 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 60 | }; 61 | //expect 62 | var mock = users.AsQueryable().BuildMock(); 63 | userRepository.GetQueryable().Returns(mock); 64 | //act 65 | var result = await service.GetUserReports(from, to); 66 | //assert 67 | Assert.AreEqual(expectedCount, result.Count); 68 | } 69 | 70 | [TestCase("01/20/2012", "06/20/2018", 5)] 71 | [TestCase("01/20/2012", "06/20/2012", 4)] 72 | [TestCase("01/20/2012", "02/20/2012", 3)] 73 | [TestCase("01/20/2010", "02/20/2011", 0)] 74 | public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) 75 | { 76 | //arrange 77 | var users = new List 78 | { 79 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 80 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 81 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 82 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 83 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 84 | }; 85 | var mock = users.AsQueryable().BuildMockDbSet(); 86 | var userRepository = new TestDbSetRepository(mock); 87 | var service = new MyService(userRepository); 88 | //act 89 | var result = await service.GetUserReportsAutoMap(from, to); 90 | //assert 91 | Assert.AreEqual(expectedCount, result.Count); 92 | 93 | } 94 | 95 | [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] 96 | [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] 97 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] 98 | public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) 99 | { 100 | //arrange 101 | var users = new List 102 | { 103 | new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 104 | new UserEntity{FirstName = "ExistFirstName"}, 105 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 106 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 107 | new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 108 | }; 109 | var mock = users.AsQueryable().BuildMockDbSet(); 110 | var userRepository = new TestDbSetRepository(mock); 111 | var service = new MyService(userRepository); 112 | //act 113 | var ex = Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); 114 | //assert 115 | Assert.AreEqual(expectedError, ex.Message); 116 | 117 | } 118 | 119 | 120 | [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] 121 | public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) 122 | { 123 | //arrange 124 | var userEntities = new List(); 125 | var mock = userEntities.AsQueryable().BuildMockDbSet(); 126 | mock.AddAsync(Arg.Any()) 127 | .Returns(info => null) 128 | .AndDoes(info => userEntities.Add(info.Arg())); 129 | var userRepository = new TestDbSetRepository(mock); 130 | var service = new MyService(userRepository); 131 | //act 132 | await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); 133 | // assert 134 | var entity = mock.Single(); 135 | Assert.AreEqual(firstName, entity.FirstName); 136 | Assert.AreEqual(lastName, entity.LastName); 137 | Assert.AreEqual(dateOfBirth, entity.DateOfBirth); 138 | } 139 | 140 | [TestCase("01/20/2012", "06/20/2018", 5)] 141 | [TestCase("01/20/2012", "06/20/2012", 4)] 142 | [TestCase("01/20/2012", "02/20/2012", 3)] 143 | [TestCase("01/20/2010", "02/20/2011", 0)] 144 | public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) 145 | { 146 | //arrange 147 | var users = new List 148 | { 149 | new UserEntity{FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 150 | new UserEntity{FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 151 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, 152 | new UserEntity{FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012",UsCultureInfo.DateTimeFormat)}, 153 | new UserEntity{FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018",UsCultureInfo.DateTimeFormat)}, 154 | }; 155 | var mock = users.AsQueryable().BuildMockDbSet(); 156 | var userRepository = new TestDbSetRepository(mock); 157 | var service = new MyService(userRepository); 158 | //act 159 | var result = await service.GetUserReports(from, to); 160 | //assert 161 | Assert.AreEqual(expectedCount, result.Count); 162 | } 163 | 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/TestDbSetRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace MockQueryable.Sample 7 | { 8 | public class TestDbSetRepository : IUserRepository 9 | { 10 | private readonly DbSet _dbSet; 11 | 12 | public TestDbSetRepository(DbSet dbSet) 13 | { 14 | _dbSet = dbSet; 15 | } 16 | public IQueryable GetQueryable() 17 | { 18 | return _dbSet; 19 | } 20 | 21 | public async Task CreateUser(UserEntity user) 22 | { 23 | await _dbSet.AddAsync(user); 24 | } 25 | 26 | public List GetAll() { 27 | return _dbSet.AsQueryable().ToList(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.Sample/TestsSetup.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace MockQueryable.Sample 4 | { 5 | [SetUpFixture] 6 | public class TestsSetup 7 | { 8 | [OneTimeSetUp] 9 | public void SetUp() 10 | { 11 | MyService.Initialize(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/MockQueryable/MockQueryable.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29102.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.Core", "MockQueryable.Core\MockQueryable.Core.csproj", "{7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.Moq", "MockQueryable.Moq\MockQueryable.Moq.csproj", "{8487D600-D0B2-42EB-80E3-2D1641847D46}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.Sample", "MockQueryable.Sample\MockQueryable.Sample.csproj", "{84563547-43DC-4A5D-AD8B-AC06166D05CF}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.NSubstitute", "MockQueryable.NSubstitute\MockQueryable.NSubstitute.csproj", "{FAAD1998-2471-45B6-9458-807B314E050F}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.FakeItEasy", "MockQueryable.FakeItEasy\MockQueryable.FakeItEasy.csproj", "{744B09F5-6F09-4F02-A09C-BD55E619C4E8}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MockQueryable.EntityFrameworkCore", "MockQueryable.EntityFrameworkCore\MockQueryable.EntityFrameworkCore.csproj", "{E3632875-02A1-4C4A-96AB-62089D9D3F4F}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {8487D600-D0B2-42EB-80E3-2D1641847D46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {8487D600-D0B2-42EB-80E3-2D1641847D46}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {8487D600-D0B2-42EB-80E3-2D1641847D46}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {8487D600-D0B2-42EB-80E3-2D1641847D46}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {84563547-43DC-4A5D-AD8B-AC06166D05CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {84563547-43DC-4A5D-AD8B-AC06166D05CF}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {84563547-43DC-4A5D-AD8B-AC06166D05CF}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {84563547-43DC-4A5D-AD8B-AC06166D05CF}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {FAAD1998-2471-45B6-9458-807B314E050F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {FAAD1998-2471-45B6-9458-807B314E050F}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {FAAD1998-2471-45B6-9458-807B314E050F}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {FAAD1998-2471-45B6-9458-807B314E050F}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {744B09F5-6F09-4F02-A09C-BD55E619C4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {744B09F5-6F09-4F02-A09C-BD55E619C4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {744B09F5-6F09-4F02-A09C-BD55E619C4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {744B09F5-6F09-4F02-A09C-BD55E619C4E8}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {E3632875-02A1-4C4A-96AB-62089D9D3F4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {E3632875-02A1-4C4A-96AB-62089D9D3F4F}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {E3632875-02A1-4C4A-96AB-62089D9D3F4F}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {E3632875-02A1-4C4A-96AB-62089D9D3F4F}.Release|Any CPU.Build.0 = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {77E46EFE-EB0A-4D83-AA83-7F79C7FFB8CC} 54 | EndGlobalSection 55 | EndGlobal 56 | --------------------------------------------------------------------------------