It is the simplest solution to test for an empty (property-less) custom object ([pscustomobject]) via its string representation, but you need to use an expandable string (string interpolation, "...") rather than .ToString() to obtain it:
# Returns $True, if custom object $test is empty, i.e. has no properties
-not "$test"
Note: -not $test.ToString() should be equivalent, but currently (as of PowerShell Core 6.1) isn't, due to a bug. With the bug present, any [pscustomobject] instance returns the empty string from.ToString().
Another workaround is to use .psobject.ToString().
Only an empty (property-less) custom object stringifies to the empty string inside an expandable string, and coercing an empty string to a Boolean in PowerShell yields $False, whereas any nonempty string yields $True.
The alternative is to compare against an empty string as the LHS, which implicitly forces the [pscustomobject] on the RHS to be stringified:
# NOTE: Works ONLY with '' on the LHS.
'' -eq $test
A conceptually clearer approach, though it relies on the hidden .psobject property PowerShell adds to all objects, containing reflection information:
0 -eq @($test.psobject.Properties).Count
Note the need to use @(...) to force enumeration of the properties so that they can be counted - see next section.
The above methods are convenient, but if $test is a large object with many properties, it can be expensive - though in absolute terms that will propbably rarely matter in practice.
A less expensive, but more obscure solution is to access the .psobject.Properties collection without enumerating all its members:
# Returns $true, if $test has no properties
-not $test.psobject.Properties.GetEnumerator().MoveNext()
The .psobject.Properties collection is apparently lazily enumerated and therefore doesn't have a .Count property; using .GetEnumerator().MoveNext() is therefore a way to limit enumeration to the first property, if any.
As for what you tried:
$test -eq $null
$test is still an object, even if it happens to have no properties, and an object is by definition never $null.
-not $test
PowerShell's implicit to-Boolean conversion treats any [pscustomobject] instance as $True, whether or not it happens to have properties; e.g., [bool] ([pscustomobject] @{}) yields $True.
To see how other data types are coerced to Booleans, see this answer.