Reputation: 25029
I want to Verify a class, but it does not have any public members. Here is the class:
public class SpreadsheetValuesList
{
private readonly List<SpreadsheetValue> _spreadsheetValues = new();
public SpreadsheetValuesList(string json)
{
_spreadsheetValues = JsonSerializer.Deserialize<List<SpreadsheetValue>>(json ?? "[]", new JsonSerializerOptions());
}
public void Add(SpreadsheetValue spreadsheetValue)
{
_spreadsheetValues.Add(spreadsheetValue);
}
public string ToJson()
{
return JsonSerializer.Serialize(_spreadsheetValues);
}
}
When I call verify on this object in a MSTest, I get this:
The Verify documentation does not seem to have anything about this, nor Stack Overflow. So I tried a few things:
ToString
method thinking that maybe Verify would call it and put it in the Test.received.txt file. It did not.public List<SpreadsheetValue> Values { get; } = new();
then it appears in the received.txt file like this:This is what I want, but I do not want to break the encapsulation of my class just so I can get a test to work. Is there a way to provide a method or attribute on a public method so Verify can output the data to the received/verified file?
This class is used as a component of other classes, so I am calling Verify on the larger class like this:
// Assert
await Verify(viewModel);
Upvotes: 1
Views: 241
Reputation: 18783
Typically you do not write unit tests for private members or methods. Instead, write tests for the public-facing behavior of your class. Some ideas that fit the philosophy of unit testing:
Write unit tests for the ToJson()
method. This might require some code gymnastics to format the expected JSON in code, but remove unnecessary formatting when comparing your expected output to the actual output.
Expose a public IEnumerable<SpreadsheetValue>
property:
public IEnumerable<SpreadsheetValue> Items => _spreadsheetValues;
Since your SpreadsheetValuesList
is logically a list, this class can implement IEnumerable<SpreadsheetValue>
directly:
public class SpreadsheetValuesList : IEnumerable<SpreadsheetValue>
{
private readonly List<SpreadsheetValue> _spreadsheetValues = new();
public SpreadsheetValuesList(string json)
{
_spreadsheetValues = JsonSerializer.Deserialize<List<SpreadsheetValue>>(json ?? "[]", new JsonSerializerOptions());
}
// Add() and ToJson() methods omitted for brevity
#region IEnumerable<T> interface
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator<SpreadsheetValue> GetEnumerator()
{
return _spreadsheetValues.GetEnumerator();
}
#endregion
}
The nice thing about option 3 is you have a functionally complete class that you can use in a foreach
loop, or use with LINQ queries:
var values = new SpreadsheetValuesList("some JSON");
foreach (var value in values)
{
// do something with value
}
This makes asserting the internals feel a little more idiomatic for C#:
var values = new SpreadsheetValuesList("some JSON");
Assert.AreEqual(2, values.Count());
Assert.AreEqual("Baz", values.First().Foo);
Don't be afraid to add additional readonly properties for other intersting internal information, like the total number of items:
public int Count => _spreadsheetValues.Count;
The main thing is to never expose the data in your class in a way that allows the outside world to mutate that data unpredictably. This keeps your tests (and code) deterministic.
Read How do you unit test private methods? for an interesting SoftwareEngineering.SE post about this same subject.
Upvotes: 1