# Serializer settings
Verify uses [Argon](https://github.com/SimonCropp/Argon) for serialization. See [Default Settings](#default-settings) for on how Argon is used and instructions on how to control that usage.
Serialization settings can be customized at three levels:
* Method: Will run the verification in the current test method.
* Class: Will run for all verifications in all test methods for a test class.
* Global: Will run for test methods on all tests.
## Not valid json
Note that the output is technically not valid json.
* Names and values are not quoted.
* Newlines are not escaped.
The reason for these is that it makes approval files cleaner and easier to read and visualize/understand differences.
### UseStrictJson
To use strict json call `VerifierSettings.UseStrictJson`:
#### Globally
```cs
[ModuleInitializer]
public static void Init() =>
VerifierSettings.UseStrictJson();
```
snippet source | anchor
#### Instance
```cs
var target = new TheTarget
{
Value = "Foo"
};
var settings = new VerifySettings();
settings.UseStrictJson();
await Verify(target, settings);
```
snippet source | anchor
#### Fluent
```cs
var target = new TheTarget
{
Value = "Foo"
};
await Verify(target)
.UseStrictJson();
```
snippet source | anchor
#### Result
Then this results in
* The default `.received.` and `.verified.` extensions for serialized verification to be `.json`.
* `JsonTextWriter.QuoteChar` to be `"`.
* `JsonTextWriter.QuoteName` to be `true`.
Then when an object is verified:
```cs
var target = new TheTarget
{
Value = "Foo"
};
await Verify(target);
```
snippet source | anchor
The resulting file will be:
```json
{
"Value": "Foo"
}
```
snippet source | anchor
## Default settings
Verify uses [Argon](https://github.com/SimonCropp/Argon) for serialization.
> Argon is a JSON framework for .NET. It is a hard fork of Newtonsoft.Json.
See [Argon documentation](https://github.com/SimonCropp/Argon/blob/main/docs/readme.md)
The default `JsonSerializerSettings` are:
```cs
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
```
snippet source | anchor
### Modify Defaults
#### Globally
```cs
VerifierSettings
.AddExtraSettings(_ =>
_.TypeNameHandling = TypeNameHandling.All);
```
snippet source | anchor
#### Instance
```cs
[Fact]
public Task AddExtraSettings()
{
var settings = new VerifySettings();
settings
.AddExtraSettings(
_ => _.SerializeError = (currentObject, originalObject, location, member, exception, handled) =>
Console.WriteLine(member));
return Verify("Value", settings);
}
```
snippet source | anchor
#### Fluent
```cs
[Fact]
public Task AddExtraSettingsFluent() =>
Verify("Value")
.AddExtraSettings(
_ => _.SerializeError = (currentObject, originalObject, location, member, exception, handled) =>
Console.WriteLine(member));
```
snippet source | anchor
## QuoteName is false
[JsonTextWriter.QuoteName](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonTextWriter_QuoteName.htm) is set to false. The reason for this is that it makes approval files cleaner and easier to read and visualize/understand differences.
## Empty collections are ignored
By default empty collections are ignored during verification.
To disable this behavior globally use:
```cs
VerifierSettings.DontIgnoreEmptyCollections();
```
snippet source | anchor
## Changing Argon settings
Extra Argon settings can be made:
### Globally
```cs
VerifierSettings.AddExtraSettings(
_ => _.TypeNameHandling = TypeNameHandling.All);
```
snippet source | anchor
### Instance
```cs
var settings = new VerifySettings();
settings.AddExtraSettings(
_ => _.TypeNameHandling = TypeNameHandling.All);
```
snippet source | anchor
### Argon Converter
One common use case is to register a custom [JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm). As only writing is required, to help with this there is `WriteOnlyJsonConverter`, and `WriteOnlyJsonConverter`.
For example given the following JsonConverter:
```cs
class CompanyConverter :
WriteOnlyJsonConverter
{
public override void Write(VerifyJsonWriter writer, Company company)
{
writer.WriteMember(company, company.Name, "Name");
writer.WriteMember(company, company.Employees, "Employees");
}
}
```
snippet source | anchor
It can be added in a ModuleInitializer:
```cs
[ModuleInitializer]
public static void Initialize() =>
VerifierSettings.AddExtraSettings(_ => _.Converters.Add(new CompanyConverter()));
```
snippet source | anchor
#### VerifyJsonWriter
A `VerifyJsonWriter` is passed in to the `Write` methods. It exposes context and helper methods to the JsonConverter. For example:
* `Counter` property that gives programmatic access to the counting behavior used by [Guid](guids.md), [Date](dates.md), and [Id](#numeric-ids-are-scrubbed) scrubbing.
* `Serializer` property that exposes the current `JsonSerializer`.
* `Serialize(object value)` is a convenience method that calls `JsonSerializer.Serialize` passing in the writer instance and the `value` parameter.
* `WriteProperty(T target, TMember value, string name)` method that writes a property name and value while respecting other custom serialization settings eg [member converters](#converting-a-member), [ignore rules](#ignoring-a-type) etc.
#### Testing JsonConverters
`WriteOnlyJsonConverter` has a `Execute` methods that executes a JsonConverter:
```cs
namespace VerifyTests;
public abstract partial class WriteOnlyJsonConverter
{
public static string Execute(
object target,
VerifySettings? settings = null)
where TConverter : WriteOnlyJsonConverter, new() =>
Execute(new TConverter(), target, settings);
public static string Execute(TConverter converter, object target, VerifySettings? settings = null)
where TConverter : WriteOnlyJsonConverter
{
settings ??= new();
settings.UseStrictJson();
var builder = new StringBuilder("{");
using var counter = Counter.Start();
using (var writer = new VerifyJsonWriter(builder, settings, counter))
{
converter.Write(writer, target);
}
builder.Append('}');
return builder.ToString();
}
}
```
snippet source | anchor
This can be used to test a JsonConverter.
Given the following JsonConverter:
```cs
class CompanyConverter :
WriteOnlyJsonConverter
{
public override void Write(VerifyJsonWriter writer, Company company)
{
writer.WriteMember(company, company.Name, "Name");
writer.WriteMember(company, company.Employees, "Employees");
}
}
```
snippet source | anchor
It can be tested with:
```cs
[Fact]
public Task Test()
{
var company = new Company(
"Company Name",
Employees:
[
"Employee1",
"Employee2"
]);
var result = WriteOnlyJsonConverter.Execute(company);
return VerifyJson(result);
}
```
snippet source | anchor
Json converters often have instance level configuration or contextual settings.
```cs
class CompanyConverter :
WriteOnlyJsonConverter
{
bool ignoreEmployees;
public CompanyConverter()
{
}
public CompanyConverter(bool ignoreEmployees) =>
this.ignoreEmployees = ignoreEmployees;
public override void Write(VerifyJsonWriter writer, Company company)
{
writer.WriteMember(company, company.Name, "Name");
if (!ignoreEmployees)
{
if (writer.Context.TryGetValue("IgnoreCompanyEmployees", out var value))
{
if (value is true)
{
return;
}
}
writer.WriteMember(company, company.Employees, "Employees");
}
}
}
```
snippet source | anchor
```cs
public static class CompanyConverterSettings
{
public static void IgnoreCompanyEmployees(this VerifySettings settings) =>
settings.Context["IgnoreCompanyEmployees"] = true;
public static SettingsTask IgnoreCompanyEmployees(this SettingsTask settings)
{
settings.CurrentSettings.IgnoreCompanyEmployees();
return settings;
}
}
```
snippet source | anchor
These can be tested:
```cs
[Fact]
public Task TestWithConverterInstance()
{
var company = new Company(
"Company Name",
Employees:
[
"Employee1",
"Employee2"
]);
var converter = new CompanyConverter(ignoreEmployees: true);
var result = WriteOnlyJsonConverter.Execute(converter, company);
return VerifyJson(result);
}
```
snippet source | anchor
```cs
[Fact]
public Task TestWithSettings()
{
var company = new Company(
"Company Name",
Employees:
[
"Employee1",
"Employee2"
]);
var settings = new VerifySettings();
settings.IgnoreCompanyEmployees();
var result = WriteOnlyJsonConverter.Execute(company, settings);
return VerifyJson(result);
}
```
snippet source | anchor
## Scoped settings
```cs
[Fact]
public Task ScopedSerializer()
{
var person = new Person
{
GivenNames = "John",
FamilyName = "Smith"
};
var settings = new VerifySettings();
settings.AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All);
return Verify(person, settings);
}
[Fact]
public Task ScopedSerializerFluent()
{
var person = new Person
{
GivenNames = "John",
FamilyName = "Smith"
};
return Verify(person)
.AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All);
}
```
snippet source | anchor
Result:
```txt
{
$type: VerifyObjectSamples.Person,
GivenNames: John,
FamilyName: Smith
}
```
snippet source | anchor
## Ignoring a type
To ignore all members that match a certain type:
```cs
[Fact]
public Task IgnoreType()
{
var target = new IgnoreTypeTarget
{
ToIgnore = new()
{
Property = "Value"
},
ToIgnoreNullable = new()
{
Property = "Value"
},
ToIgnoreByInterface = new()
{
Property = "Value"
},
ToIgnoreByBase = new()
{
Property = "Value"
},
ToIgnoreByBaseGeneric = new()
{
Property = "Value"
},
ToIgnoreByType = new()
{
Property = "Value"
},
ToInclude = new()
{
Property = "Value"
},
ToIncludeNullable = new()
{
Property = "Value"
},
ToIgnoreStruct = new("Value"),
ToIgnoreStructNullable = new("Value"),
ToIncludeStruct = new("Value"),
ToIncludeStructNullable = new("Value")
};
var settings = new VerifySettings();
settings.IgnoreMembersWithType();
settings.IgnoreMembersWithType();
settings.IgnoreMembersWithType();
settings.IgnoreMembersWithType();
settings.IgnoreMembersWithType(typeof(BaseToIgnoreGeneric<>));
settings.IgnoreMembersWithType();
return Verify(target, settings);
}
[Fact]
public Task IgnoreTypeFluent()
{
var target = new IgnoreTypeTarget
{
ToIgnore = new()
{
Property = "Value"
},
ToIgnoreNullable = new()
{
Property = "Value"
},
ToIgnoreByInterface = new()
{
Property = "Value"
},
ToIgnoreByBase = new()
{
Property = "Value"
},
ToIgnoreByBaseGeneric = new()
{
Property = "Value"
},
ToIgnoreByType = new()
{
Property = "Value"
},
ToInclude = new()
{
Property = "Value"
},
ToIncludeNullable = new()
{
Property = "Value"
},
ToIgnoreStruct = new("Value"),
ToIgnoreStructNullable = new("Value"),
ToIncludeStruct = new("Value"),
ToIncludeStructNullable = new("Value")
};
return Verify(target)
.IgnoreMembersWithType()
.IgnoreMembersWithType()
.IgnoreMembersWithType()
.IgnoreMembersWithType()
.IgnoreMembersWithType(typeof(BaseToIgnoreGeneric<>))
.IgnoreMembersWithType();
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.IgnoreMembersWithType();
```
snippet source | anchor
Result:
```txt
{
ToInclude: {
Property: Value
},
ToIncludeNullable: {
Property: Value
},
ToIncludeStruct: {
Property: Value
},
ToIncludeStructNullable: {
Property: Value
}
}
```
snippet source | anchor
## Scrub a type
To scrub all members that match a certain type:
```cs
[Fact]
public Task ScrubType()
{
var target = new IgnoreTypeTarget
{
ToIgnore = new()
{
Property = "Value"
},
ToIgnoreNullable = new()
{
Property = "Value"
},
ToIgnoreByInterface = new()
{
Property = "Value"
},
ToIgnoreByBase = new()
{
Property = "Value"
},
ToIgnoreByBaseGeneric = new()
{
Property = "Value"
},
ToIgnoreByType = new()
{
Property = "Value"
},
ToInclude = new()
{
Property = "Value"
},
ToIncludeNullable = new()
{
Property = "Value"
},
ToIgnoreStruct = new("Value"),
ToIgnoreStructNullable = new("Value"),
ToIncludeStruct = new("Value"),
ToIncludeStructNullable = new("Value")
};
var settings = new VerifySettings();
settings.ScrubMembersWithType();
settings.ScrubMembersWithType();
settings.ScrubMembersWithType();
settings.ScrubMembersWithType();
settings.ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>));
settings.ScrubMembersWithType();
return Verify(target, settings);
}
[Fact]
public Task ScrubTypeFluent()
{
var target = new IgnoreTypeTarget
{
ToIgnore = new()
{
Property = "Value"
},
ToIgnoreNullable = new()
{
Property = "Value"
},
ToIgnoreByInterface = new()
{
Property = "Value"
},
ToIgnoreByBase = new()
{
Property = "Value"
},
ToIgnoreByBaseGeneric = new()
{
Property = "Value"
},
ToIgnoreByType = new()
{
Property = "Value"
},
ToInclude = new()
{
Property = "Value"
},
ToIncludeNullable = new()
{
Property = "Value"
},
ToIgnoreStruct = new("Value"),
ToIgnoreStructNullable = new("Value"),
ToIncludeStruct = new("Value"),
ToIncludeStructNullable = new("Value")
};
return Verify(target)
.ScrubMembersWithType()
.ScrubMembersWithType()
.ScrubMembersWithType()
.ScrubMembersWithType()
.ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>))
.ScrubMembersWithType();
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.ScrubMembersWithType();
```
snippet source | anchor
Result:
```txt
{
ToIgnore: {Scrubbed},
ToIgnoreByType: {Scrubbed},
ToIgnoreByInterface: {Scrubbed},
ToIgnoreByBase: {Scrubbed},
ToIgnoreByBaseGeneric: {Scrubbed},
ToIgnoreNullable: {Scrubbed},
ToIgnoreStruct: {Scrubbed},
ToIgnoreStructNullable: {Scrubbed},
ToInclude: {
Property: Value
},
ToIncludeNullable: {
Property: Value
},
ToIncludeStruct: {
Property: Value
},
ToIncludeStructNullable: {
Property: Value
}
}
```
snippet source | anchor
## Ignoring an instance
To ignore instances of a type based on delegate:
```cs
[Fact]
public Task AddIgnoreInstance()
{
var target = new IgnoreInstanceTarget
{
ToIgnore = new()
{
Property = "Ignore"
},
ToInclude = new()
{
Property = "Include"
}
};
var settings = new VerifySettings();
settings.IgnoreInstance(_ => _.Property == "Ignore");
return Verify(target, settings);
}
[Fact]
public Task AddIgnoreInstanceFluent()
{
var target = new IgnoreInstanceTarget
{
ToIgnore = new()
{
Property = "Ignore"
},
ToInclude = new()
{
Property = "Include"
}
};
return Verify(target)
.IgnoreInstance(_ => _.Property == "Ignore");
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore");
```
snippet source | anchor
Result:
```txt
{
ToInclude: {
Property: Include
}
}
```
snippet source | anchor
## Scrub a instance
To scrub instances of a type based on delegate:
```cs
[Fact]
public Task AddScrubInstance()
{
var target = new IgnoreInstanceTarget
{
ToIgnore = new()
{
Property = "Ignore"
},
ToInclude = new()
{
Property = "Include"
}
};
var settings = new VerifySettings();
settings.ScrubInstance(_ => _.Property == "Ignore");
return Verify(target, settings);
}
[Fact]
public Task AddScrubInstanceFluent()
{
var target = new IgnoreInstanceTarget
{
ToIgnore = new()
{
Property = "Ignore"
},
ToInclude = new()
{
Property = "Include"
}
};
return Verify(target)
.ScrubInstance(_ => _.Property == "Ignore");
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.ScrubInstance(_ => _.Property == "Ignore");
```
snippet source | anchor
Result:
```txt
{
ToIgnore: {Scrubbed},
ToInclude: {
Property: Include
}
}
```
snippet source | anchor
## Ignore member by expressions
To ignore members of a certain type using an expression:
```cs
[Fact]
public Task IgnoreMemberByExpression()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyWithPropertyName = "Value"
};
var settings = new VerifySettings();
settings.IgnoreMembers(
_ => _.Property,
_ => _.PropertyWithPropertyName,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
return Verify(target, settings);
}
[Fact]
public Task IgnoreMemberByExpressionFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value"
};
return Verify(target)
.IgnoreMembers(
_ => _.Property,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
}
```
snippet source | anchor
Or globally
```cs
VerifierSettings.IgnoreMembers(
_ => _.Property,
_ => _.PropertyWithPropertyName,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
```
snippet source | anchor
Result:
```txt
{
Include: Value
}
```
snippet source | anchor
## Scrub member by expressions
To scrub members of a certain type using an expression:
```cs
[Fact]
public Task ScrubMemberByExpression()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyWithPropertyName = "Value"
};
var settings = new VerifySettings();
settings.ScrubMembers(
_ => _.Property,
_ => _.PropertyWithPropertyName,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
return Verify(target, settings);
}
[Fact]
public Task ScrubMemberByExpressionFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value"
};
return Verify(target)
.ScrubMembers(
_ => _.Property,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
}
```
snippet source | anchor
Or globally
```cs
VerifierSettings.ScrubMembers(
_ => _.Property,
_ => _.PropertyWithPropertyName,
_ => _.Field,
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
```
snippet source | anchor
Result:
```txt
{
Field: {Scrubbed},
Include: Value,
Property: {Scrubbed},
_Custom: {Scrubbed},
GetOnlyProperty: {Scrubbed},
PropertyThatThrows: {Scrubbed}
}
```
snippet source | anchor
## Ignore member by name
To ignore members of a certain type using type and name:
```cs
[Fact]
public Task IgnoreMemberByName()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
// For all types
settings.IgnoreMember("PropertyByName");
// For a specific type
settings.IgnoreMember(typeof(IgnoreExplicitTarget), "Property");
// For a specific type generic
settings.IgnoreMember("Field");
// For a specific type with expression
settings.IgnoreMember(_ => _.PropertyThatThrows);
return Verify(target, settings);
}
[Fact]
public Task IgnoreMemberByNameFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
return Verify(target)
// For all types
.IgnoreMember("PropertyByName")
// For a specific type
.IgnoreMember(typeof(IgnoreExplicitTarget), "Property")
// For a specific type generic
.IgnoreMember("Field")
// For a specific type with expression
.IgnoreMember(_ => _.PropertyThatThrows);
}
```
snippet source | anchor
Or globally:
```cs
// For all types
VerifierSettings.IgnoreMember("PropertyByName");
// For a specific type
VerifierSettings.IgnoreMember(typeof(IgnoreExplicitTarget), "Property");
// For a specific type generic
VerifierSettings.IgnoreMember("Field");
// For a specific type with expression
VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows);
```
snippet source | anchor
Result:
```txt
{
Include: Value,
GetOnlyProperty: asd
}
```
snippet source | anchor
## Scrub member by name
To scrub members of a certain type using type and name:
```cs
[Fact]
public Task ScrubMemberByName()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
// For all types
settings.ScrubMember("PropertyByName");
// For a specific type
settings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
// For a specific type generic
settings.ScrubMember("Field");
// For a specific type with expression
settings.ScrubMember(_ => _.PropertyThatThrows);
return Verify(target, settings);
}
[Fact]
public Task ScrubMemberByNameFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
return Verify(target)
// For all types
.ScrubMember("PropertyByName")
// For a specific type
.ScrubMember(typeof(IgnoreExplicitTarget), "Property")
// For a specific type generic
.ScrubMember("Field")
// For a specific type with expression
.ScrubMember(_ => _.PropertyThatThrows);
}
```
snippet source | anchor
Or globally:
```cs
// For all types
VerifierSettings.ScrubMember("PropertyByName");
// For a specific type
VerifierSettings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
// For a specific type generic
VerifierSettings.ScrubMember("Field");
// For a specific type with expression
VerifierSettings.ScrubMember(_ => _.PropertyThatThrows);
```
snippet source | anchor
Result:
```txt
{
Field: {Scrubbed},
Include: Value,
Property: {Scrubbed},
PropertyByName: {Scrubbed},
GetOnlyProperty: asd,
PropertyThatThrows: {Scrubbed}
}
```
snippet source | anchor
## Ignore member by predicate
To ignore members of a certain type using a predicate function:
```cs
[Fact]
public Task IgnoreMemberByPredicate()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
settings.IgnoreMembers(_ => _ is "Field" or "Property");
settings.IgnoreMembers(_ => _.Name is "PropertyByName" or "PropertyThatThrows");
return Verify(target, settings);
}
[Fact]
public Task IgnoreMemberByPredicateFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
return Verify(target, settings)
.IgnoreMembers(_ => _ is "Field" or "Property")
.IgnoreMembers(_ => _.Name is "PropertyByName" or "PropertyThatThrows");
}
[Fact]
public Task IgnoreDictionaryByPredicate()
{
var settings = new VerifySettings();
settings.IgnoreMembers(name => name is "Ignore");
var target = new Dictionary
{
{
"Include", new Dictionary
{
{
"Ignore", "Value1"
},
{
"Key1", "Value2"
}
}
},
{
"Ignore", "Value3"
},
{
"Key2", "Value4"
}
};
return Verify(target, settings);
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.IgnoreMembers(
_=>_.DeclaringType == typeof(TargetClass) &&
_.Name == "Proprty");
```
snippet source | anchor
Result:
```txt
{
Include: Value,
GetOnlyProperty: asd
}
```
snippet source | anchor
## Scrub member by predicate
To scrub members of a certain type using a predicate function:
```cs
[Fact]
public Task ScrubMemberByPredicate()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
settings.ScrubMembers(_ => _ is "Field" or "Property");
settings.ScrubMembers(_ => _.Name is "PropertyByName" or "PropertyThatThrows");
return Verify(target, settings);
}
[Fact]
public Task ScrubMemberByPredicateFluent()
{
var target = new IgnoreExplicitTarget
{
Include = "Value",
Field = "Value",
Property = "Value",
PropertyByName = "Value"
};
var settings = new VerifySettings();
return Verify(target, settings)
.ScrubMembers(name => name is "Field" or "Property")
.ScrubMembers(member => member.Name is "PropertyByName" or "PropertyThatThrows");
}
[Fact]
public Task ScrubDictionaryByPredicate()
{
var settings = new VerifySettings();
settings.ScrubMembers(name => name is "Ignore");
var target = new Dictionary
{
{
"Include", new Dictionary
{
{
"Ignore", "Value1"
},
{
"Key1", "Value2"
}
}
},
{
"Ignore", "Value3"
},
{
"Key2", "Value4"
}
};
return Verify(target, settings);
}
```
snippet source | anchor
Or globally:
```cs
VerifierSettings.ScrubMembers(
_=>_.DeclaringType == typeof(TargetClass) &&
_.Name == "Proprty");
```
snippet source | anchor
Result:
```txt
{
Field: {Scrubbed},
Include: Value,
Property: {Scrubbed},
PropertyByName: {Scrubbed},
GetOnlyProperty: asd,
PropertyThatThrows: {Scrubbed}
}
```
snippet source | anchor
## Converting a member
The value of a member can be mutated before serialization:
```cs
[ModuleInitializer]
public static void MemberConverterByExpressionInit()
{
// using only the member
VerifierSettings.MemberConverter(
expression: _ => _.Field,
converter: _ => $"{_}_Suffix");
// using target and member
VerifierSettings.MemberConverter(
expression: _ => _.Property,
converter: (target, member) => $"{target}_{member}_Suffix");
}
[Fact]
public Task MemberConverterByExpression()
{
var input = new MemberTarget
{
Field = "FieldValue",
Property = "PropertyValue"
};
return Verify(input);
}
```
snippet source | anchor
## See also
* [Obsolete members](/docs/obsolete-members.md)
* [Type to string mapping](/docs/type-to-string-mapping.md)
* [Guids](/docs/guids.md)
* [Dates](/docs/dates.md)
* [Scrubbing](/docs/scrubbers.md)
* [Members that throw](/docs/members-throw.md)
* [Ordering](/docs/ordering.md)
* [Encoding](/docs/encoding.md)
* [JsonAppender](/docs/jsonappender.md)